package com.iot08.api.service;

import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONArray;
import com.alibaba.fastjson.JSONObject;
import com.iot08.api.config.properties.CommonProperties;
import com.iot08.api.config.redis.RedisClusterService;
import com.iot08.api.config.redis.RedisFilterService;
import com.iot08.api.constant.Constant;
import com.iot08.api.response.DeviceFunctionResp;
import com.iot08.api.response.HomePageCommand;
import com.iot08.api.response.SetWifiInfoResp;
import com.iot08.api.response.VipEnjoyAloneFunction;
import com.iot08.api.service.supplement.KafkaService;
import com.iot08.api.service.supplement.WeixinService;
import com.iot08.api.utils.StringTool;
import com.iot08.api.utils.buckettool.BaseBucketTool;
import com.iot08.api.utils.ContentSecurityUtil;
import com.iot08.api.utils.RuiJiIOTUtil;
import com.iot08.api.vo.request.*;
import com.iot08.api.vo.request.base.BaseAccountReqVO;
import com.iot08.common.config.mongodb.query.UpdateVO;
import com.iot08.common.constant.*;
import com.iot08.common.entity.app.*;
import com.iot08.common.service.base.BaseService;
import com.iot08.common.utils.*;
import com.iot08.common.utils.response.ResponseEnum;
import com.iot08.common.utils.response.ResponseMap;
import com.mongodb.client.model.Filters;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.codec.digest.DigestUtils;
import org.apache.commons.collections4.CollectionUtils;
import org.apache.commons.collections4.MapUtils;
import org.apache.commons.lang3.ObjectUtils;
import org.apache.commons.lang3.StringUtils;
import org.bson.Document;
import org.bson.types.ObjectId;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.data.mongodb.core.query.Criteria;
import org.springframework.data.mongodb.core.query.Query;
import org.springframework.data.mongodb.core.query.Update;
import org.springframework.stereotype.Service;
import org.springframework.web.multipart.MultipartFile;

import javax.annotation.Resource;
import java.io.IOException;
import java.util.*;
import java.util.concurrent.TimeUnit;

/**
 * @version 1.0
 * @Description: 设备相关业务逻辑
 * @author: Rock
 * @time: 2020/11/4 10:00
 */
@Slf4j
@Service
public class DeviceService extends BaseService<Device> {

    @Resource
    private ModelsService modelsService;
    @Resource
    private RedisFilterService redisFilterService;
    @Resource
    private RedisClusterService redisClusterService;
    @Resource
    private AccountService accountService;
    @Resource
    private BaseBucketTool baseBucketTool;
    @Resource
    private PpChatGroupService ppChatGroupService;
    @Resource
    private ChatGroupService chatGroupService;

    @Resource
    //单群聊
    private SingleChatGroupService singleChatGroupService;

    @Resource
    private CommonProperties commonProperties;
    @Resource
    private KafkaService kafkaService;
    @Resource
    private WeixinService weixinService;
    @Resource
    private IotCardInfoService iotCardInfoService;
    @Resource
    private ResetDeviceService resetDeviceService;
    @Resource
    private DeviceMessageService deviceMessageService;
    @Resource
    private DeviceNotificationService deviceNotificationService;
    @Resource
    private DeviceAttentionService deviceAttentionService;
    @Resource
    private DeviceLocationService deviceLocationService;
    @Resource
    private DeviceLocationDailyService deviceLocationDailyService;
    @Resource
    private DeviceStepDailyService deviceStepDailyService;
    @Resource
    private DeviceCostFlowService deviceCostFlowService;
    @Resource
    private DeviceDataFlowService deviceDataFlowService;
    @Resource
    private PpChatGroupMessageService ppChatGroupMessageService;
    @Resource
    private HeartRateRecordService heartRateRecordService;
    @Resource
    private BloodPressureRecordService bloodPressureRecordService;
    @Resource
    private BloodOxygenRecordService bloodOxygenRecordService;
    @Resource
    private HeartRateSettingService heartRateSettingService;
    @Resource
    private BloodPressureSettingService bloodPressureSettingService;
    @Resource
    private BloodOxygenSettingService bloodOxygenSettingService;
    //体温
    @Resource
    private AnimalHeatSettingService animalHeatSettingService;
    @Resource
    private AnimalHeatRecordService animalHeatRecordService;
    @Resource
    private DevicePhotographService devicePhotographService;
    @Resource
    private DevModelAndUseURLService devModelAndUseURLService;
    @Resource
    private DeviceSedentaryService deviceSedentaryService;
    @Resource
    private DeviceCmsgService deviceCmsgService;

    @Resource
    private DeviceSanWordService deviceSanWordService;

    @Resource
    private UserKeyActionService userKeyActionService;

    @Resource
    private DeviceResetAsyncService deviceResetAsyncService;

    @Resource
    private SetWifiService setWifiService;

    @Resource
    private CallRecordService callRecordService;

    @Resource
    private WechatContactService wechatContactService;

    @Resource
    private DeviceAppManagerService deviceAppManagerService;


    @Value("${watch.store.channel.url: }")
    private String watchStoreChannelUrl;

    //默认设备的使用指南URL
    @Value("${default.use.url}")
    private String defaultUseURL;

    //======艾拉比 OTA 版本信息获取参数=========
    // : 表示如果找不到默认使用 "" 空字符串
    @Value("${ALB_OTA.VersionReqURL:}")
    private String ALB_OTAVersionReqURL;

    @Value("${ALB_OTA.devModelMapJSONStr:}")
    private String ALB_OTADevModelMapJSONStr;



    /**
     * @param device
     * @param account
     * @param chatGroup
     * @time: 2020/11/4 16:25
     * @author: Rock
     * @version 1.0
     */
    public void addAccount(Device device, Account account, ChatGroup chatGroup) {
        if (device.getUserMap() == null) {
            device.setUserMap(new HashMap<>());
        }
        Update update = new Update();
        if (device.getSos() == null) {
            //建立设备与用户关联
            device.setSos(new HashMap<>());
            Double now = DateUtil.nowTimestampToDouble();
            Map<String, Object> temp = new HashMap<>();
            temp.put("phone", "");
            temp.put("t", now);
            //默认三个
            device.getSos().put(RandomUtil.getRandomStr(8), temp);
            device.getSos().put(RandomUtil.getRandomStr(8), temp);
            device.getSos().put(RandomUtil.getRandomStr(8), temp);
            update.set("s", device.getSos());
        }
        Map<String, Object> sub = new HashMap<>();
        sub.put("t", DateUtil.nowTimestampToDouble());
        sub.put("g", chatGroup.getId());
        device.getUserMap().put(account.getId(), sub);
        update.set("u", device.getUserMap());
        this.updateById(device.getId(), update);
    }

    /**
     * 添加群（包含update操作）
     *
     * @param device
     * @param openId
     * @time: 2020/11/4 16:34
     * @author: Rock
     * @version 1.0
     */
    public void addChatGroup(Device device, String openId) {
        if (device.getChatGroupMap() == null) {
            device.setChatGroupMap(new HashMap<>());
        }
        Map<String, Object> sub = new HashMap<>();
        sub.put("t", DateUtil.nowTimestampToDouble());
        device.getChatGroupMap().put(openId, sub);
        Update update = new Update();
        update.set("g", device.getChatGroupMap());
        this.updateById(device.getId(), update);
    }

    /**
     * @param openid
     * @param ids
     * @time: 2020/11/9 16:32
     * @author: Rock
     * @version 1.0
     */
    public void delAccountHandle(String openid, Set<String> ids) {
        List<Device> deviceList = this.listByIds(ids);
        for (Device d : deviceList) {
            if (CollectionUtil.removeMapKey(d.getUserMap(), openid)) {
                UpdateVO update = new UpdateVO();
                update.setMap("u", d.getUserMap());
                this.updateById(d.getId(), update);
            }
        }
    }

    /**
     * @param chatGroupId
     * @param ids
     * @time: 2020/12/21 10:37
     * @author: Rock
     * @version 1.0
     */
    public void delChatGroup(String chatGroupId, Set<String> ids) {
        List<Device> deviceList = this.listByIds(ids);
        for (Device device : deviceList) {
            if (device != null && CollectionUtil.removeMapKey(device.getChatGroupMap(), chatGroupId)) {
                UpdateVO update = new UpdateVO();
                update.setMap("g", device.getChatGroupMap());
                this.updateById(device.getId(), update);
            }
        }
    }

    /**
     * @description 设置设备指令功能
     * @author cwj
     * @param [device, data]
     * @return void
     * @date @time 2025/1/10 9:51
     **/
    public void settingDeviceFunction(Device device, Map<String, Object> data){
        if (device == null) {
            return;
        }
        List<DeviceFunctionResp> deviceFunctionResps = new ArrayList<>();
        String modelId = device.getModelId();
        if(modelId != null){
            Models modelsObj = modelsService.findById(modelId);
            if(ObjectUtils.isNotEmpty(modelsObj)){
                String modules = modelsObj.getModules();
                String vipEnjoyAloneStr = modelsObj.getVipEnjoyAlone();
                String homePageStr = modelsObj.getPlaceHomePage();
                VipEnjoyAloneFunction veaf = new VipEnjoyAloneFunction();
                HomePageCommand hpc = new HomePageCommand();
                //初始化属性值为0
                veaf.settingVipEnjoyAloneFunction(veaf, vipEnjoyAloneStr);
                hpc.settingHomePageCommand(hpc,homePageStr);
                //设置设备的Vip独享功能
                if(StringUtils.isNotEmpty(modules)){
                    //根据modules内容设置指令功能
                    settingFunctionByModules(modules, deviceFunctionResps, veaf, hpc);
                }
                //根据状态设置指令功能
                settingFunctionByStatus(deviceFunctionResps, modelsObj, veaf, hpc);
            }
        } else {
            // 非型号的使用默认的
            assembleDeviceFunction(deviceFunctionResps,"vedio",1, 0,1,"视频通话");
            assembleDeviceFunction(deviceFunctionResps,"tk", 1, 0,1,"微聊");
            assembleDeviceFunction(deviceFunctionResps,"flower", 1, 0,0,"小红花");
            assembleDeviceFunction(deviceFunctionResps,"costFlow", 1, 0,0,"查询话费流量");
            assembleDeviceFunction(deviceFunctionResps,"find",1, 0,0,"找设备");
        }
        data.put("deviceFunctions",deviceFunctionResps);
    }


    /**
     * @description
     * @author cwj
     * @param [device]
     * @return com.iot08.common.utils.response.ResponseMap
     * @date @time 2025/1/14 11:17
     **/
    public ResponseMap queryDeviceFunction(Device device){
        if (device == null) {
            return ResponseMap.fail("设备不存在");
        }
        ResponseMap res = ResponseMap.success();
        List<DeviceFunctionResp> deviceFunctionResps = new ArrayList<>();
        String modelId = device.getModelId();
        if(modelId != null){
            Models modelsObj = modelsService.findById(modelId);
            if(ObjectUtils.isNotEmpty(modelsObj)){
                String modules = modelsObj.getModules();
                String vipEnjoyAloneStr = modelsObj.getVipEnjoyAlone();
                String homePageStr = modelsObj.getPlaceHomePage();
                VipEnjoyAloneFunction veaf = new VipEnjoyAloneFunction();
                HomePageCommand hpc = new HomePageCommand();
                //初始化属性值为0
                veaf.settingVipEnjoyAloneFunction(veaf, vipEnjoyAloneStr);
                hpc.settingHomePageCommand(hpc,homePageStr);
                //设置设备的Vip独享功能
                if(StringUtils.isNotEmpty(modules)){
                    //根据modules内容设置指令功能
                    settingFunctionByModules(modules, deviceFunctionResps ,veaf,hpc);
                }
                //根据状态设置指令功能
                settingFunctionByStatus(deviceFunctionResps, modelsObj, veaf,hpc);
            }
        } else {
            // 非型号的使用默认的
            assembleDeviceFunction(deviceFunctionResps,"vedio",1, 0,1,"视频通信");
            assembleDeviceFunction(deviceFunctionResps,"tk", 1, 0,1,"微聊");
            assembleDeviceFunction(deviceFunctionResps,"flower", 1, 0,0,"小红花");
            //assembleDeviceFunction(deviceFunctionResps,"costFlow", 1, 0,0,"查询话费流量");
            assembleDeviceFunction(deviceFunctionResps,"find",1, 0,0,"找设备");
        }
        res.put("deviceFunctions",deviceFunctionResps);
        return res;
    }

    /**
     * @description 根据状态设置指令功能
     * @author cwj
     * @param [deviceFunctionResps, modelsObj, veaf]
     * @return void
     * @date @time 2025/1/10 15:04
     **/
    private void settingFunctionByStatus(List<DeviceFunctionResp> deviceFunctionResps, Models modelsObj, VipEnjoyAloneFunction veaf,HomePageCommand hpc) {
        assembleDeviceFunction(deviceFunctionResps,"find",(modelsObj.getOpfind() != null && modelsObj.getOpfind() == 1)?1:0, veaf.getIsFindEnjoy(),hpc.getIsFindHp(),"找设备");
        assembleDeviceFunction(deviceFunctionResps,"dialswitch",
                (modelsObj.getOpdialswitch() != null && modelsObj.getOpdialswitch() == 1)?1:0, veaf.getIsDialSwitchEnjoy(),hpc.getIsDialSwitchHp(),"拨号盘开关");
        assembleDeviceFunction(deviceFunctionResps,"flower", modelsObj.getOpFlower() != null ? modelsObj.getOpFlower():0, veaf.getIsFlowerEnjoy(),hpc.getIsFlowerHp(),"小红花");
        //assembleDeviceFunction(deviceFunctionResps,"costFlow", modelsObj.getCostFlow() != null ? modelsObj.getCostFlow():0, veaf.getIsCostFlowEnjoy(),hpc.getIsCostFlowHp(),"查询话费流量");
        assembleDeviceFunction(deviceFunctionResps,"inquireCharge", modelsObj.getCostFlow() != null ? modelsObj.getCostFlow():0, veaf.getIsCostFlowEnjoy(),hpc.getIsCostFlowHp(),"查询话费流量");
        assembleDeviceFunction(deviceFunctionResps,"schoolTimeTable",
                (modelsObj.getOpSchoolTimeTable() != null && modelsObj.getOpSchoolTimeTable() == 1) ?1:0, veaf.getIsSchoolTimeTableEnjoy(),hpc.getIsSchoolTimeTableHp(),"课程表");
        assembleDeviceFunction(deviceFunctionResps,"voucherCenter",
                (modelsObj.getOpVoucherCenter() != null && modelsObj.getOpVoucherCenter() == 1) ?1:0, veaf.getIsVoucherCenterEnjoy(),hpc.getIsVoucherCenterHp(),"充值中心");
        assembleDeviceFunction(deviceFunctionResps,"heartRate",
                (modelsObj.getOpHeartRate() != null && modelsObj.getOpHeartRate() == 1) ?1:0, veaf.getIsHeartRateEnjoy(),hpc.getIsHeartRateHp(),"心率");
        assembleDeviceFunction(deviceFunctionResps,"temperature",
                (modelsObj.getOpTemperature() != null && modelsObj.getOpTemperature() == 1) ?1:0, veaf.getIsTemperatureEnjoy(),hpc.getIsTemperatureHp(),"体温");
        assembleDeviceFunction(deviceFunctionResps,"timingSwitch",
                (modelsObj.getOpTimingSwitch() != null && modelsObj.getOpTimingSwitch() == 1) ?1:0, veaf.getIsTimingSwitchEnjoy(),hpc.getIsTimingSwitchHp(),"定时开关机");
        assembleDeviceFunction(deviceFunctionResps,"ppmf",
                (modelsObj.getPpmfmodules() != null && modelsObj.getPpmfmodules() == 1) ?1:0, veaf.getIsPpmfEnjoy(),hpc.getIsPpmfHp(),"砰砰交好友");
        assembleDeviceFunction(deviceFunctionResps,"dicpenCloudType",
                (modelsObj.getOpDicpenCloudType() != -1) ? modelsObj.getOpDicpenCloudType():0, veaf.getIsDicPenCloudTypeEnjoy(),hpc.getIsDicPenCloudTypeHp(),"云词本类型");
    }

    /**
     * @description 根据modules设置功能
     * @author cwj
     * @param [modules, deviceFunctionResps, veaf]
     * @return void
     * @date @time 2025/1/10 14:21
     **/
    private void settingFunctionByModules(String modules, List<DeviceFunctionResp> deviceFunctionResps, VipEnjoyAloneFunction veaf,HomePageCommand hpc) {
        String name = "video";
        String desc = "视频通话";
        if (modules.contains(ConstVideo.V0JF)) {
            assembleDeviceFunction(deviceFunctionResps,name,4, veaf.getIsVideoEnjoy(),hpc.getIsVideoHp(),desc);
        } else if (modules.contains(ConstVideo.V0SW)) {
            assembleDeviceFunction(deviceFunctionResps,name,1, veaf.getIsVideoEnjoy(),hpc.getIsVideoHp(),desc);
        } else if (modules.contains(ConstVideo.V0VM)) {
            assembleDeviceFunction(deviceFunctionResps,name,5, veaf.getIsVideoEnjoy(),hpc.getIsVideoHp(),desc);
        }else{
            assembleDeviceFunction(deviceFunctionResps,name,0, veaf.getIsVideoEnjoy(),hpc.getIsVideoHp(),desc);
        }
        assembleDeviceFunction(deviceFunctionResps,"location", (modules.contains("L0")||modules.contains("L1")||modules.contains("L2")||modules.contains("L3"))?1:0,
                veaf.getIsLocationEnjoy(),hpc.getIsLocationHp(),"定位");
        assembleDeviceFunction(deviceFunctionResps,"photo", modules.contains("P0")?1:0, veaf.getIsPhotoEnjoy(),hpc.getIsPhotoHp(),"拍照");
        assembleDeviceFunction(deviceFunctionResps,"step", modules.contains("S0")?1:0, veaf.getIsStepEnjoy(),hpc.getIsStepHp(),"计步");
        assembleDeviceFunction(deviceFunctionResps,"tk", modules.contains("C0")?1:0, veaf.getIsChatEnjoy(),hpc.getIsChatHp(),"微聊");
        assembleDeviceFunction(deviceFunctionResps,"wifi", modules.contains("W0")?1:0, veaf.getIsWifiEnjoy(),hpc.getIsWifiHp(),"WIFI");
        assembleDeviceFunction(deviceFunctionResps,"drink_water", modules.contains("D0")?1:0, veaf.getIsDrinkWaterEnjoy(),hpc.getIsDrinkWaterHp(),"喝水提醒");
        assembleDeviceFunction(deviceFunctionResps,"sedentariness", modules.contains("E0")?1:0, veaf.getIsSedentarinessEnjoy(),hpc.getIsSedentarinessHp(),"久坐提醒");
        assembleDeviceFunction(deviceFunctionResps,"app_manager", modules.contains("M0")?1:0, veaf.getIsAppManagerEnjoy(),hpc.getIsAppManagerHp(),"应用监管");
        assembleDeviceFunction(deviceFunctionResps,"agent_sms", modules.contains("A0")?1:0, veaf.getIsAgenetSmsEnjoy(),hpc.getIsAgenetSmsHp(),"短信代收");
        assembleDeviceFunction(deviceFunctionResps,"auto_call", modules.contains("T0")?1:0, veaf.getIsAutoCallEnjoy(),hpc.getIsAutoCallHp(),"自动接听");
        assembleDeviceFunction(deviceFunctionResps,"screensavor", modules.contains("R0")?1:0, veaf.getIsScreensavorEnjoy(),hpc.getIsScreensavorHp(),"专属屏保");
        assembleDeviceFunction(deviceFunctionResps,"phoneBook",modules.contains("B0")?1:0, veaf.getIsPhoneBookEnjoy(),hpc.getIsPhoneBookHp(),"电话本");
        assembleDeviceFunction(deviceFunctionResps,"alock",modules.contains("K0")?1:0, veaf.getIsAlockEnjoy(),hpc.getIsAlockHp(),"闹钟");
        assembleDeviceFunction(deviceFunctionResps,"classForbidden",modules.contains("F0")?1:0, veaf.getIsClassForbiddenEnjoy(),hpc.getIsClassForbiddenHp(),"上课禁用");
        assembleDeviceFunction(deviceFunctionResps,"SOS",modules.contains("O0")?1:0, veaf.getIsSosEnjoy(),hpc.getIsSosHp(),"SOS");
        assembleDeviceFunction(deviceFunctionResps,"restart",modules.contains("G0")?1:0, veaf.getIsRestartEnjoy(),hpc.getIsRestartHp(),"重启");
        assembleDeviceFunction(deviceFunctionResps,"close",modules.contains("H0")?1:0, veaf.getIsClockEnjoy(),hpc.getIsClockHp(),"远程关机");
        assembleDeviceFunction(deviceFunctionResps,"callRecord",modules.contains("I0")?1:0, veaf.getIsCallRecordEnjoy(),hpc.getIsCallRecordHp(),"通话记录");
        assembleDeviceFunction(deviceFunctionResps,"wallpaper",modules.contains("J0")?1:0, veaf.getIsWallpaperEnjoy(),hpc.getIsWallpaperHp(),"壁纸商城");
        assembleDeviceFunction(deviceFunctionResps,"rejectStrangeCall",modules.contains("N0")?1:0, veaf.getIsRejectStrangeCall(),hpc.getIsRejectStrangeCallHp(),"陌生来电拦截");
        assembleDeviceFunction(deviceFunctionResps,"powerSaving",modules.contains("Q0")?1:0, veaf.getIsPowerSaving(),hpc.getIsPowerSavingHp(),"夜间省电");
        assembleDeviceFunction(deviceFunctionResps,"sleepDetection",modules.contains("U0")?1:0, veaf.getIsSleepDetection(),hpc.getIsSleepDetectionHp(),"睡眠检测");
    }



    /**
     * @description
     * @author cwj
     * @param [deviceFunctionResps, name, isSupport, isVipEnjoyAlone]
     * @return void
     * @date @time 2025/1/10 10:36
     **/
    private void assembleDeviceFunction(List<DeviceFunctionResp> deviceFunctionResps,String name,Integer isSupport,Integer isVipEnjoyAlone,Integer isPlaceHomePage,String desc) {
        DeviceFunctionResp deviceFunctionResp = new DeviceFunctionResp();
        deviceFunctionResp.setName(name);
        deviceFunctionResp.setIsSupport(isSupport);
        deviceFunctionResp.setIsVipEnjoyAlone(isVipEnjoyAlone);
        deviceFunctionResp.setIsPlaceHomepage(isPlaceHomePage);
        deviceFunctionResp.setDesc(desc);
        deviceFunctionResps.add(deviceFunctionResp);
    }

    /**
     * 检查 设备上传的功能模块的字符串 , 返回功能列表
     *
     * @param device
     * @time: 2020/11/10 11:32
     * @author: Rock
     * @version 1.0
     */
    public void checkDeviceFunctions(Device device, Map<String, Object> data) {
        if (device == null) {
            return;
        }
        if (StringUtil.isNotBlank(device.getModules())) {
            if (device.getModules().contains(ConstVideo.V0JF)) {
                data.put("support_video", 4);
            } else if (device.getModules().contains(ConstVideo.V0SW)) {
                data.put("support_video", 1);
            } else if (device.getModules().contains(ConstVideo.V0VM)) {
                data.put("support_video", 5);
            }else{
                data.put("support_video", 0);
            }
        }else{
            //没有视频功能的 赋0
            data.put("support_video", 0);
        }
        String modelId = device.getModelId();
        if(modelId != null){
            Models modelsOB = modelsService.findById(modelId);
            if (modelsOB.getIsWatchCustomFunction() != null && Const.INT_1.equals(modelsOB.getIsWatchCustomFunction()))
            {
                if (StringUtil.isNotBlank(device.getWatchCustomFunction())) {
                    //有自动功能配置
                    String devUpFunStr = device.getWatchCustomFunction();
                    data.put("watchCustomFunction", device.getWatchCustomFunction());
                    String jsonStr = "{\n" +
                            "\t\"support_photo\": \"P0\",\n" +
                            "\t\"support_tk\": \"TK\",\n" +
                            "\t\"support_addBook\": \"AB\",\n" +
                            "\t\"support_clock\": \"CK\",\n" +
                            "\t\"support_DND\": \"DND\",\n" +
                            "\t\"support_ML\": \"ML\",\n" +
                            "\t\"support_SNTS\": \"SNTS\",\n" +
                            "\t\"support_HTF\": \"HTF\",\n" +
                            "\t\"support_RS\": \"RS\",\n" +
                            "\t\"support_SOS\": \"SOS\",\n" +
                            "\t\"support_GF\": \"GF\",\n" +
                            "\t\"support_RESET\": \"RESET\",\n" +
                            "\t\"support_wifi\": \"WIFI\",\n" +
                            "\t\"support_ppmf\": \"PPMF\",\n" +
                            "\t\"support_step\": \"S0\",\n" +
                            "\t\"support_dataFlow\": \"DF\",\n" +
                            "\t\"support_costFlow\": \"CF\",\n" +
                            "\t\"support_dialswitch\": \"DW\",\n" +
                            "\t\"watchStoreChannelId\": \"APPM:\",\n" +
                            "\t\"support_find\": \"FD\",\n" +
                            "\t\"support_temperature\": \"TEMP\",\n" +
                            "\t\"support_heartRate\": \"HR\",\n" +
                            "\t\"support_flower\": \"EC\",\n" +
                            "\t\"support_schoolTimeTable\": \"CCList\",\n" +
                            "\t\"support_voucherCenter\": \"VC\",\n" +
                            "\t\"support_timingSwitch\": \"TS\"\n" +
                            "}";
                    JSONObject defKeyValueMap = JSONObject.parseObject(jsonStr);
                    String[] tempStrList = devUpFunStr.replace(" ", "").split(",");
                    for (String key : defKeyValueMap.keySet()) {
                        String value = defKeyValueMap.getString(key);
                        for (String strValue: tempStrList) {
                            if(strValue.contains("APPM:")){
                                String[] strValueSplit = strValue.split(":");
                                data.put("watchStoreChannelId",strValueSplit[strValueSplit.length-1]);
                            }else if (value.equals(strValue)){
                                data.put(key, 1);
                                break;
                            }else{
                                if(!key.equals("watchStoreChannelId")){
                                    data.put(key, 0);
                                }
                            }
                        }
                    }
                }
            }
            else
            {
                //不是自动配置使用 型号的配置
                //设置拍照、计步、微聊、wifi、喝水、久坐、应用监管等功能的设置
                settingDataByModules(device.getModules(), data);
                if(modelsOB.getOpfind() != null && modelsOB.getOpfind() == 1){
                    data.put("support_find", 1);
                }
                if(modelsOB.getOpdialswitch() != null && modelsOB.getOpdialswitch() == 1){
                    data.put("support_dialswitch", 1);
                }
                if(modelsOB.getOpFlower() == null) {
                    data.put("support_flower", 1);
                }else{
                    data.put("support_flower", modelsOB.getOpFlower());
                }
                if(modelsOB.getCostFlow() == null) {
                    data.put("support_costFlow", 1);
                }else{
                    data.put("support_costFlow", modelsOB.getCostFlow());
                }

                if(modelsOB.getOpSchoolTimeTable() != null && modelsOB.getOpSchoolTimeTable() == 1){
                    data.put("support_schoolTimeTable", 1);
                }
                if(modelsOB.getOpVoucherCenter() != null && modelsOB.getOpVoucherCenter() == 1){
                    data.put("support_voucherCenter", 1);
                }
                if(modelsOB.getOpHeartRate() != null && modelsOB.getOpHeartRate() == 1){
                    data.put("support_heartRate", 1);
                }
                if(modelsOB.getOpTemperature() != null && modelsOB.getOpTemperature() == 1){
                    data.put("support_temperature", 1);
                }
                if(modelsOB.getOpTimingSwitch() != null && modelsOB.getOpTimingSwitch() == 1){
                    data.put("support_timingSwitch", 1);
                }
                if(modelsOB.getPpmfmodules() != null && modelsOB.getPpmfmodules() == 1){
                    data.put("support_ppmf", 1);
                }
            }
            if(modelsOB.getOpDicpenCloudType() != -1) {
                data.put("support_dicpenCloudType", modelsOB.getOpDicpenCloudType());
            }
        }
        else
        {
            // 非型号的使用默认的
            settingDataByModules(device.getModules(), data);
            if(device.getOpfind() != null){
                data.put("support_find", device.getOpfind());
            }
            if(device.getDialSwitch() != null){
                data.put("support_dialswitch", 1);
            }
            data.put("support_flower", 1);
            data.put("support_costFlow", 1);
        }

//        //赋值型号和设备使用指南
//        String devModel = device.getDevModel();
//        if(devModel != null){
//            data.put("devModel",devModel);
//            DevModelAndUseURL byDevModel = devModelAndUseURLService.findByDevModel(devModel);
//            if(byDevModel != null){
//                data.put("devUseURL",byDevModel.getUrl());
//            }else{
//                data.put("devUseURL",defaultUseURL);
//            }
//        }

    }

    /**
     * @description 设置拍照、计步、微聊、wifi、喝水、久坐、应用监管等功能的设置
     * @author cwj
     * @param [modules, data]
     * @return void
     * @date @time 2024/11/9 11:37
     **/
    private static void settingDataByModules(String modules, Map<String, Object> data) {
        if(modules != null){
            if(modules.contains("P0")){
                data.put("support_photo", 1);
            }
            if(modules.contains("S0")){
                data.put("support_step", 1);
            }
            if(modules.contains("C0")){
                data.put("support_tk", 1);
            }
            if(modules.contains("W0")) {
                data.put("support_wifi", 1);
            }
            if(modules.contains("D0")) {
                data.put("support_drink_water", 1);
            }
            if(modules.contains("E0")) {
                data.put("support_sedentariness", 1);
            }
            if(modules.contains("W0")) {
                data.put("support_app_manager", 1);
            }
            if(modules.contains("A0")) {
                data.put("support_agent_sms",1);
            }
            if(modules.contains("T0")) {
                data.put("support_auto_call",1);
            }
            if(modules.contains("R0")) {
                data.put("support_screensavor",1);
            }
        }
    }

    /**
     * 添加关联设备
     * @param device
     * @param account
     * @param chatGroupId
     * @time: 2020/11/12 18:00
     * @author: Rock
     * @version 1.0
     */
    //public void addAccountHandle(Device device, Account account, String chatGroupId, UpdateVO updateDevice, AddRelatedDeviceReqBodyFormVO vo) {
    public Map<String, Object> addAccountHandle(Device device, Account account, String chatGroupId, UpdateVO updateDevice, AddRelatedDeviceReqBodyFormVO vo) {
        Map<String, Object> sub = new HashMap<>();
        Integer maxSerialNum = null;
        Integer currentSerialNum = 0;
        String maxSerialNumRedisValue = redisFilterService.get(device.getId()+Constant.MAX_SERIAL_NUM_KEY_POSTFIX);
        if(StringUtils.isNotEmpty(maxSerialNumRedisValue)) {
            maxSerialNum = Integer.valueOf(maxSerialNumRedisValue);
        }
        //检查设备家庭成员或联系人有无序列号
        if(isSerialNumNull(device)) {
            //更新设备绑定人（家庭成员的编号）
            int index = updateDeviceUserSerialNo(device,device.getUserMap(), updateDevice);
            //更新设备联系人的编号
            index = updeteDeviceContactSerialNo(device,device.getContactMap(), index, updateDevice);
            maxSerialNum = index;
            maxSerialNum++;
            currentSerialNum = maxSerialNum;
        } else {
            //检查有无删除掉的序列号
            List<Map<String, Object>> allContactList = new ArrayList<>();
            //合并联系人数据
            assembleAllContactData(device, allContactList);
            //根据编号进行排序
            if(CollectionUtils.isNotEmpty(allContactList)) {
                //按从小到达顺序进行排序
                CollectionUtil.sortByKeyType(allContactList, "serialNum", 2);
                //遍历数组，取出其中空出的数据进行设置
                currentSerialNum = getCurrentSerialNum(allContactList, currentSerialNum);
                if(currentSerialNum.equals(0)) {
                    currentSerialNum = allContactList.size() + 1;
                    maxSerialNum = allContactList.size() + 1;
                } else {
                    if(ObjectUtils.isEmpty(maxSerialNum)) {
                        maxSerialNum = allContactList.size() + 1;
                    } else {
                        maxSerialNum++;
                    }
                }
            } else {
                maxSerialNum = 1;
                currentSerialNum = 1;
            }
        }
        //重置缓存当前
        redisFilterService.set(device.getId()+Constant.MAX_SERIAL_NUM_KEY_POSTFIX,maxSerialNum.toString());
        sub.put("serialNum",currentSerialNum);
        sub.put("t", System.currentTimeMillis() / 1000d);
        sub.put("g", chatGroupId);
        sub.put("c", account.getId());
        sub.put("phone", account.getPhone());
        sub.put("relationship", vo.getRelationship());
        sub.put("relationship_image_id", vo.getRelationship_image_id());
        //默认是成员
        sub.put("identity", "member");
        Map<String, Map<String, Object>> oldUserMap = device.getUserMap();
        if (oldUserMap == null) {
            oldUserMap = new HashMap<>();
            //如果是第一个的话,那么就是管理员
            sub.put("identity", "admin");
        }
        for (String key: oldUserMap.keySet()) {
            JSONObject item = new JSONObject(oldUserMap.get(key));
            if(item.containsKey("identity") && "admin".equals(item.getString("identity")) ){
                sub.put("identity", "member");
            }
        }
        if(oldUserMap.size() == 1){
            //如果只有一个的且为 游客的情况,要成为管理员
            for (String key: oldUserMap.keySet()) {
                JSONObject item = new JSONObject(oldUserMap.get(key));
                if(item.containsKey("identity") && "visitor".equals(item.getString("identity")) ){
                    sub.put("identity", "admin");
                }
            }
        }
        oldUserMap.put(account.getId(), sub);
        updateDevice.setMap("u", oldUserMap);
        //TODO 添加关联设备的时候 (绑定设备的时候) 同时也增加一下视频联系人,如果这个设备有视频功能的话 modules字段包含 "V0"
        if (device.getModules() != null && device.getModules().contains("V0")) {
            Map<String, Map<String, Object>> checkedOpenidsMap = device.getCheckedOpenidsMap();
            if (checkedOpenidsMap == null) {
                checkedOpenidsMap = new HashMap<>();
//                device.setCheckedOpenidsMap(new HashMap<>());
            }
            checkedOpenidsMap.put(account.getId(), sub);
            device.setCheckedOpenidsMap(checkedOpenidsMap);
            updateDevice.setMap("checked_openids", checkedOpenidsMap);
        }

        // TODO 这里要暂时兼容Python 版本的 添加设备关联时需要在通讯录中添加一个通讯录人员
        String cid = RandomUtil.getRandomStr(8);
        sub.put("openid", account.getId());
        sub.put("name", sub.get("relationship"));
        sub.put("image", sub.get("relationship_image_id"));
        // 绑定关联时默认能视频
        sub.put("canVideo", 1);
        Map<String, Map<String, Object>> contactMap = device.getContactMap();
        if (contactMap == null) {
            contactMap = new HashMap<>();
//                device.setCheckedOpenidsMap(new HashMap<>());
        }
        contactMap.put(cid, sub);
        updateDevice.setMap("c", contactMap);
        //如果具有短标识 三基的设备, 需要更新视频联系人
        if (device.getModules().contains(ConstVideo.V0JF)) {
            // 有菊风视频
            String shortId = RedisClusterService.getJedisCluster().hget(device.getId(), "shortId");
            if (StringUtils.isNotBlank(shortId)) {
                //三基的短标识设备
                JSONObject kafkaJson = new JSONObject();
                if(!ObjectUtils.isEmpty(device.getIsNewWechatProtocol()) && device.getIsNewWechatProtocol().equals(1)) {
                    kafkaJson.put("name",vo.getRelationship());
                    //kafkaJson.put("phone",account.getPhone());
                    kafkaJson.put("openId",account.getId());
                    String wechatAvator = "";
                    //没有上传图像则用旧图像，旧图像不存在或是默认图像则没有图像，暂时不发头像，没搞清楚协议中图像数据的发送的编码
                    if (StringUtil.isNotBlank(account.getImage()) && !account.getImage().contains("default.jpg")){
                        wechatAvator =  BaseBucketTool.ACCOUNT_COMMON_PATH + account.getImage();
                        if(!"ASR".equals(device.getPlatform())) {
                            kafkaJson.put("avator", "/" + wechatAvator);
                        }
                    }
                    log.info("新版协议添加微聊联系人及视频联系人的指令，指令数据为：{}",kafkaJson);
                    //发送视频微聊联系人指令
                    kafkaService.emitDeviceDemand(device.getId(), ConstKafka.DEVICE_TYPE_ADD_NEW_CONTACT, kafkaJson, vo.getOpenid());
                    //保存或更新微聊联系人，保存数据时存全路径
                    wechatContactService.saveOrUpdateWechatContact(device.getId(),account.getPhone(),account.getId(),chatGroupId,
                            vo.getRelationship(), StringUtils.isNotEmpty(wechatAvator) ? (baseBucketTool.getDOMAIN() + wechatAvator):wechatAvator);
                } else {
                    kafkaJson.put("openid", account.getId());
                    kafkaJson.put("phone", account.getPhone());
                    kafkaJson.put("name", sub.get("relationship"));
                    kafkaJson.put("relationship", sub.get("relationship"));
                    kafkaJson.put("relationship_image_id", sub.get("relationship_image_id"));
                    log.info("旧版协议添加微聊联系人及视频联系人的指令，指令数据为：{}",kafkaJson);
                    kafkaService.emitDeviceDemand(device.getId(), ConstKafka.DEVICE_TYPE_DownAddVideoContact, kafkaJson, null);
                }
            }
        }

        //如果 设备没有3个SOS 那么建立3个空的
        if (!CollectionUtil.isNotEmpty(device.getSos())) {
            //建立设备与用户关联
            device.setSos(new HashMap<>());
            Double now = DateUtil.nowTimestampToDouble();
            Map<String, Object> temp = new HashMap<>();
            temp.put("phone", "");
            temp.put("t", now);
            //默认三个
            device.getSos().put(RandomUtil.getRandomStr(8), temp);
            device.getSos().put(RandomUtil.getRandomStr(8), temp);
            device.getSos().put(RandomUtil.getRandomStr(8), temp);
            updateDevice.set("s", device.getSos());
        }
        return sub;
    }


    /**
     * @description 检查编号是否有过缺失
     * @author cwj
     * @param [allContactList]
     * @return java.lang.Integer
     * @date @time 2025/6/18 10:56
     **/
    private boolean checkeSerialNumDeficiency(List<Map<String, Object>> allContactList) {
        //查找前面的编号中是否存在等于i+1的
        boolean hasSerialNumDeficiency = false;
        for(int i = 0; i< allContactList.size(); i++){
            Map<String,Object> map = allContactList.get(i);
            if(ObjectUtils.isNotEmpty(map.get("serialNum"))) {
                Integer serialNum = (Integer) map.get("serialNum");
                if(!serialNum.equals(i + 1)) {
                    hasSerialNumDeficiency = true;
                }
            }
        }
        return hasSerialNumDeficiency;
    }

    
    /**
     * @description 获取当前设备编码
     * @author cwj
     * @param [allContactList, currentSerialNum]
     * @return java.lang.Integer
     * @date @time 2025/6/15 16:14
     **/
    private Integer getCurrentSerialNum(List<Map<String, Object>> allContactList, Integer currentSerialNum) {
        for(int i = 0; i< allContactList.size(); i++){
            Map<String,Object> map = allContactList.get(i);
            if(ObjectUtils.isNotEmpty(map.get("serialNum"))) {
                Integer serialNum = (Integer) map.get("serialNum");
                if(!serialNum.equals(i + 1)) {
                    if(i == 0) {
                        currentSerialNum = i+1;
                        break;
                    } else {
                        //查找前面的编号中是否存在等于i+1的
                        boolean hasExistsSerialNum = false;
                        for(int j=0;j<i;j++) {
                            Map<String,Object> tempMap = allContactList.get(j);
                            if(ObjectUtils.isNotEmpty(tempMap.get("serialNum"))){
                                Integer tempSerialNum = (Integer) tempMap.get("serialNum");
                                if(tempSerialNum.equals(i+1)){
                                    hasExistsSerialNum = true;
                                    break;
                                }
                            }
                        }
                        if(!hasExistsSerialNum) {
                            currentSerialNum = i+1;
                            break;
                        }
                    }
                }
            }
        }
        return currentSerialNum;
    }

    /**
     * @param device
     * @param chatGroupId
     * @time: 2021/1/8 14:43
     * @author: Rock
     * @version 1.0
     */
    public void addChatGroupHandle(Device device, String chatGroupId, UpdateVO updateDevice) {
        if (device.getChatGroupMap() == null) {
            device.setChatGroupMap(new HashMap<>());
        }
        Map<String, Object> sub = new HashMap<>();
        sub.put("t", System.currentTimeMillis() / 1000d);
        device.getChatGroupMap().put(chatGroupId, sub);
        updateDevice.setMap("g", device.getChatGroupMap());
    }

    /**
     * 修改设备信息
     *
     * @param imei
     * @param vo
     * @time: 2020/11/30 21:41
     * @author: Rock
     * @version 1.0
     */
    public ResponseMap updateInfo(String imei, DeviceUpdateInfoReqVO vo, MultipartFile image) throws IOException {
        Device device = this.findById(imei);
        if (device == null) {
            log.error("Device is null. _id={}", imei);
            return ResponseMap.fail(ResponseEnum.STATUS2001.getCode(), ResponseEnum.STATUS2001.getMsg(), imei);
        }
        Account account = accountService.findById(vo.getOpenid());
        if(ObjectUtils.isEmpty(account)) {
            log.error("Account is null. id={}. param is vo={}", vo.getOpenid(), vo);
            return ResponseMap.fail(ResponseEnum.STATUS2000.getCode(), ResponseEnum.STATUS2000.getMsg());
        }
        ResponseMap data = ResponseMap.success();
        UpdateVO updateDevice = new UpdateVO();
        //是否有更新 名字/电话 如果有的话, 有碰碰交友需要同步
        boolean updateName = false;
        boolean updatePhone = false;
        boolean updateImage = false;
        String avator = "";
        if (StringUtil.isNotBlank(vo.getName()) && !vo.getName().equals(device.getName())) {
            //检查 设备昵称
            boolean res = ContentSecurityUtil.nicknameAudit(vo.getName());
            if(!res){
                //昵称包含敏感词汇
                userKeyActionService.add(10, vo.getOpenid(), "设备:"+imei+" 昵称包含敏感词汇:"+vo.getName());
                return ResponseMap.fail(ResponseEnum.STATUS400.getCode(), "昵称包含敏感词汇,请纠正");
            }
            updateDevice.set("name", vo.getName());
            updateName = true;
        }
        if (StringUtil.isNotBlank(vo.getPhone()) && !vo.getPhone().equals(device.getPhone())) {
            updateDevice.set("phone", vo.getPhone());
            updatePhone = true;
        }
        if (StringUtil.isNotBlank(vo.getGrade()) && !vo.getGrade().equals(device.getGrade())) {
            updateDevice.set("grade", vo.getGrade());
        }
        if (StringUtil.isNotBlank(vo.getSex()) && !vo.getSex().equals(device.getSex())) {
            updateDevice.set("sex", vo.getSex());
        }
        if (StringUtil.isNotBlank(vo.getBirthday()) && !vo.getBirthday().equals(device.getBirthday())) {
            updateDevice.set("birthday", vo.getBirthday());
        }
        if (StringUtil.isNotBlank(vo.getWeight())) {
            updateDevice.set("weight", Integer.valueOf(vo.getWeight()));
        }
        if (StringUtil.isNotBlank(vo.getHeight())) {
            updateDevice.set("height", Integer.valueOf(vo.getHeight()));
        }
        if (StringUtil.isNotBlank(vo.getRelationship()) && StringUtil.isNotBlank(vo.getRelationship_image_id())) {
            //检查名称和关系是否有变更
            try{
                //更新绑定关系
                JSONObject userSub = new JSONObject(device.getUserMap().get(vo.getOpenid()));
                String oldRelationship = userSub.getString( "relationship");
                Integer oldRelationshipImageId = userSub.getInteger("relationship_image_id");
                if(!oldRelationship.equals(vo.getRelationship())  ||  oldRelationshipImageId != vo.getRelationship_image_id()){
                    Long time = DateUtil.nowTimestampToLong();
                    userSub.put("t", time);
                    userSub.put("relationship", vo.getRelationship());
                    userSub.put("relationship_image_id", vo.getRelationship_image_id());
                    //设置更新 家庭成员
                    device.getUserMap().put(vo.getOpenid(), userSub);
                    updateDevice.setMap("u", device.getUserMap());
                    if (CollectionUtil.containsKey(device.getCheckedOpenidsMap(), vo.getOpenid())) {
                        //看看是否是在视频通话联系人中,是的话要更新信息
                        device.getCheckedOpenidsMap().put(vo.getOpenid(), userSub);
                        updateDevice.setMap("checked_openids", device.getCheckedOpenidsMap());
                        if (device.getModules().contains(ConstVideo.V0JF)) {
                            // 有菊风视频
                            String shortId = RedisClusterService.getJedisCluster().hget(device.getId(), "shortId");
                            if (StringUtils.isNotBlank(shortId)) {
                                JSONObject kafkaJson = new JSONObject();
                                //新版微聊协议
                                if(!ObjectUtils.isEmpty(device.getIsNewWechatProtocol()) && device.getIsNewWechatProtocol().equals(1)) {
                                    //下发修改联系人的名字的指令
                                    kafkaJson.put("name",vo.getRelationship());
                                  //  kafkaJson.put("phone",account.getPhone());
                                    kafkaJson.put("openId",account.getId());
                                    //更新设备跟用户的绑定关系中的名字
                                    wechatContactService.updateWechatContactName(device.getId(),account.getId(),vo.getRelationship());
                                    //下发更新新版微聊协议的微聊-视频的联系人信息
                                    kafkaService.emitDeviceDemand(device.getId(),ConstKafka.DEVICE_TYPE_UPDATE_NEW_CONTACT_NAME,kafkaJson,vo.getOpenid());
                                } else {
                                    //三基的短标识设备，旧版微聊协议
                                    kafkaJson.put("openid", vo.getOpenid());
                                    kafkaJson.put("phone", userSub.getString("phone"));
                                    kafkaJson.put("name", vo.getRelationship());
                                    kafkaJson.put("relationship", vo.getRelationship());
                                    kafkaJson.put("relationship_image_id", vo.getRelationship_image_id());
                                    kafkaService.emitDeviceDemand(device.getId(), ConstKafka.DEVICE_TYPE_DownAddVideoContact, kafkaJson, null);
                                }
                            }
                        }
                    }
                }
            }catch (Exception e){
                log.error("imei:"+imei+" 更新绑定关系时错误 error:"+e.getMessage(), e);
            }
        }

        if (image != null && !image.isEmpty()) {
            String oldImageName = device.getImage();
            if (StringUtil.isNotBlank(oldImageName) && !oldImageName.contains("default.jpg")) {
                //删除旧文件
                baseBucketTool.delFile(BaseBucketTool.DEVICE_COMMON_PATH + oldImageName);
            }
            //生成文件名并上传
            String fileName = BaseBucketTool.createFileNameToJpg();
            baseBucketTool.upload(BaseBucketTool.DEVICE_COMMON_PATH + fileName, image, 1);

            //检查 设备头像
            boolean res = ContentSecurityUtil.imageAudit(baseBucketTool.getDOMAIN() + BaseBucketTool.DEVICE_COMMON_PATH + fileName, imei);
            if(!res){
                //头像包含敏感头像
                //删除敏感头像
//                baseBucketTool.delFile(BaseBucketTool.DEVICE_COMMON_PATH + fileName);
                userKeyActionService.add(10, vo.getOpenid(), "设备:"+imei+" 修改头像,违规:"+baseBucketTool.getDOMAIN() + BaseBucketTool.DEVICE_COMMON_PATH + fileName);
                return ResponseMap.fail(ResponseEnum.STATUS400.getCode(), "不能上传此头像,请纠正");
            }
            updateDevice.set("image", fileName);
            avator = "/" + BaseBucketTool.DEVICE_COMMON_PATH + fileName;
            updateImage = true;
            data.put("avator", baseBucketTool.getDOMAIN() + BaseBucketTool.DEVICE_COMMON_PATH + fileName);
        }
        //更新操作
        this.updateById(imei, updateDevice);
        //是否有更新 设备 名字/电话 如果有的话, 有碰碰交友需要同步
        if (updateName || updatePhone || updateImage) {
            if(ObjectUtils.isNotEmpty(device.getIsNewWechatProtocol()) && device.getIsNewWechatProtocol().equals(1) && MapUtils.isNotEmpty(device.getPpFriends())) {
                if(updateImage)
                {
                    for (String key : device.getPpFriends().keySet()) {
                        Device dev = this.findById(key);
                        if(!"ASR".equals(dev.getPlatform())) {
                            JSONObject kafkaJson = new JSONObject();
                            kafkaJson.put("id", imei.substring(4, 14));
                            kafkaJson.put("phone", updatePhone?vo.getPhone():device.getPhone());
                            kafkaJson.put("avator",avator);
                            kafkaService.emitDeviceDemand(key,ConstKafka.DEVICE_TYPE_PP_FRIEND_UPDATE_AVATOR,kafkaJson,vo.getOpenid());
                        }
                    }
                }
                if (updateName || updatePhone){
                    for (String key : device.getPpFriends().keySet()) {
                        JSONObject kafkaJson = new JSONObject();
                        kafkaJson.put("id", imei.substring(4, 14));
                        kafkaJson.put("phone", updatePhone?vo.getPhone():device.getPhone());
                        kafkaJson.put("name",updateName?vo.getName():device.getName());
                        kafkaService.emitDeviceDemand(key,ConstKafka.DEVICE_TYPE_PP_FRIEND_UPDATE_PHONE_NAME,kafkaJson,vo.getOpenid());
                    }
                }
            }

           /* if(device.getWatchCustomFunction() != null && device.getWatchCustomFunction().contains("PPMF")){
                //修改设备资料
                PpChatGroup ppChatGroup = ppChatGroupService.getByImei(imei);
                if (ppChatGroup != null && CollectionUtil.isNotEmpty(ppChatGroup.getMemberMap())) {
                    for (String key : ppChatGroup.getMemberMap().keySet()) {
                        PpChatGroup cg = ppChatGroupService.getByImei(key);
                        if (cg != null) {
                            ppChatGroupService.addMember(cg, imei);
                            JSONObject json = new JSONObject();
                            json.put("syncfriends", ppChatGroupService.getFriends(cg));
                            kafkaService.emitDeviceDemand(key, ConstKafka.DEVICE_TYPE_DownSyncFriend, json, vo.getOpenid());
                        }
                    }
                }
            }*/
        }

        userKeyActionService.add(9, vo.getOpenid(), "修改设备资料"+device.getId());
        return data;
    }

    /**
     * 获取设备信息 设备基本信息
     *
     * @param imei
     * @time: 2020/12/1 14:18
     * @author: Rock
     * @version 1.0
     */
    public ResponseMap getInfo(String imei) {
        if (!RegexUtil.validateDeviceId(imei)) {
            log.warn("imei is exception. id={}. getInfo", imei);
            return ResponseMap.fail(ResponseEnum.STATUS2001.getCode(), ResponseEnum.STATUS2001.getMsg(), imei);
        }
        Device device = this.findById(imei);
        if (device == null) {
            log.error("Device is null. id={}. getInfo", imei);
            return ResponseMap.fail(ResponseEnum.STATUS2001.getCode(), ResponseEnum.STATUS2001.getMsg(), imei);
        }
//        if (StringUtil.isBlank(device.getToken())
//                && StringUtil.isBlank(redisClusterService.hget(imei, ConstCacheField.TOKEN))) {
//            return ResponseMap.fail(ResponseEnum.STATUS600.getCode(), ResponseEnum.STATUS600.getMsg());
//        }
        ResponseMap data = ResponseMap.success();
        data.put("imei", imei);
        data.put("vendor", StringUtil.isBlank(device.getVendor()) ? 20000 : device.getVendor());
        data.put("name", getDeviceName(device));
        data.put("phone", device.getPhone());
        data.put("avator", baseBucketTool.getDOMAIN() + BaseBucketTool.DEVICE_COMMON_PATH
                + (StringUtil.isBlank(device.getImage()) ? Const.DEFAULT_JPG : device.getImage()));
        data.put("sex", device.getSex());
        data.put("grade", device.getGrade());
        data.put("birthday", device.getBirthday());
        data.put("battery", device.getBattery());
        data.put("model",device.getModel());
        String onlineStatus = redisClusterService.hget(imei, ConstCacheField.ONLINE_STATUS);
        if(onlineStatus != null){
            data.put("onlineStatus", Integer.valueOf(onlineStatus));
        }else{
            data.put("onlineStatus", 0);
        }
        data.put("accountNum", device.getUserMap() == null ? 0 : device.getUserMap().size());
        if (StringUtil.isNotBlank(device.getPlatform())) {
            data.put("platform", device.getPlatform());
        }
        List<Map<String, Object>> chatGroupList = new ArrayList<>();
        if (CollectionUtil.isNotEmpty(device.getChatGroupMap())) {
            for (String key : device.getChatGroupMap().keySet()) {
                Map<String, Object> temp = new HashMap<>();
                temp.put("id", key);
                chatGroupList.add(temp);
            }
        } else {
            Map<String, Object> temp = new HashMap<>();
            temp.put("id", "imei:" + imei);
            chatGroupList.add(temp);
        }
        if (Const.INT_1.equals(device.getIsWatchCustomFunction()) && StringUtil.isNotBlank(device.getWatchCustomFunction())
                && device.getWatchCustomFunction().contains("DEVTYPE:")) {
            String[] tempArr = device.getWatchCustomFunction().split("DEVTYPE:");
            tempArr = tempArr[tempArr.length - 1].split(",");
            if (StringUtil.isNumeric(tempArr[0])) {
                data.put("devOrientGroup", Integer.parseInt(tempArr[0]));
            }
        }
        data.put("chatGroupList", chatGroupList);
        //单聊群组ID 允许前端自行 拼接  accountId+"&"+imei
        return data;
    }


    /**
     * @description wifi搜索
     * @author cwj
     * @param [imei]
     * @return com.iot08.common.utils.response.ResponseMap
     * @date @time 2024/12/18 17:20
     **/
    public ResponseMap searchWifiInfo(String imei,BaseAccountReqVO vo){
        //检查设备是否在线，不在线不能下发
        String onlineStatus = redisClusterService.hget(imei, ConstCacheField.ONLINE_STATUS);
        if (!"1".equals(onlineStatus)) {
            return ResponseMap.fail(ResponseEnum.STATUS5001.getCode(), ResponseEnum.STATUS5001.getMsg());
        }
        String key = Constant.WIFI_SEARCH_PREFIX+imei;
        String wifiData = redisFilterService.get(key);
        ResponseMap res = ResponseMap.success();
        List<WifiInfo> wifiInfos = new ArrayList<>();
        res.put("wifiInfos",wifiInfos);
        if(!StringUtils.isEmpty(wifiData)){
            String[] wifiDatas = wifiData.split(",");
            for(int i=0;i<wifiDatas.length-1;i=i+2){
                WifiInfo wi = new WifiInfo();
                wi.setName(wifiDatas[i]);
                wi.setSsid(wifiDatas[i+1]);
                wifiInfos.add(wi);
            }
            if(CollectionUtils.isNotEmpty(wifiInfos)){
                res.put("wifiInfos",wifiInfos);
            }
        }else{
            //缓存调用的openId,用于推送消息给指定对象
            String openIdKey = Constant.WIFI_SEARCH_OPENID_PREFIX+imei;
            //可能多人同时操作，这种情况比较少,设置缓存的openid
            setCacheIds(vo.getOpenid(), openIdKey);
            //下发搜索WIFI的指令
            kafkaService.emitDeviceDemand(imei, ConstKafka.DEV_WIFI_SEARCH, new JSONObject(),vo.getOpenid());
        }
        return res;
    }

    /**
     * @description 设置缓存的openId或id
     * @author cwj
     * @param [vo, openIdKey]
     * @return void
     * @date @time 2024/12/24 9:49
     **/
    private void setCacheIds(String id, String key) {
        String ids = redisFilterService.get(key);
        if(StringUtils.isEmpty(ids)){
            redisFilterService.set(key, id);
        } else {
            ids += ","+ id;
            redisFilterService.set(key,ids);
        }
    }

    /**
     * 获取设备WIFI
     *
     * @param imei
     * @time: 2020/12/2 11:15
     * @author: Rock
     * @version 1.0
     */
    public ResponseMap getWifiInfo(String imei) {
        Device device = this.findById(imei);
        if (device == null) {
            log.error("Device is null. _id={}", imei);
            return ResponseMap.fail(ResponseEnum.STATUS2001.getCode(), ResponseEnum.STATUS2001.getMsg(), imei);
        }
        ResponseMap data = ResponseMap.success();
        String modules = device.getModules();
        if (StringUtil.isNotBlank(device.getWatchCustomFunction())) {
            modules = device.getWatchCustomFunction();
        }
        if (modules == null || (!modules.contains("W0") && !modules.contains("WIFI")) ) {
            return ResponseMap.fail(ResponseEnum.STATUS403.getCode(), "API.request.wifi.notWIFI");
        }
        //查询给设备设置的wifi信息
        List<SetWifiInfoResp> setWifiInfo = setWifiService.querySetWifiInfoList(imei);
        data.put("settingWifiInfo",setWifiInfo);
        return data;
    }

    /**
     * 设置设备WIFI
     *
     * @param imei
     * @param vo
     * @time: 2020/12/2 11:44
     * @author: Rock
     * @version 1.0
     */
    public ResponseMap settingWifiInfo(String imei, DeviceUpdateWifiInfoReqVO vo) {
        //检查设备是否在线，不在线不能下发
        String onlineStatus = redisClusterService.hget(imei, ConstCacheField.ONLINE_STATUS);
        if (!"1".equals(onlineStatus)) {
            return ResponseMap.fail(ResponseEnum.STATUS5001.getCode(), ResponseEnum.STATUS5001.getMsg());
        }
        Device device = findById(imei);
        if (device == null) {
            log.error("Device is null. _id={}", imei);
            return ResponseMap.fail(ResponseEnum.STATUS2001.getCode(), ResponseEnum.STATUS2001.getMsg(), imei);
        }
        String modules = device.getModules();
        if (StringUtil.isNotBlank(device.getWatchCustomFunction())) {
            modules = device.getWatchCustomFunction();
        }
        if (StringUtil.isBlank(modules) || (!modules.contains("W0") && !modules.contains("WIFI")) ) {
            return ResponseMap.fail(ResponseEnum.STATUS403.getCode(), "API.request.wifi.notWIFI");
        }
        //缓存指令发送人，推送消息时用以确认给谁推送消息
        String openIdKey = Constant.WIFI_SET_OPENID_PREFIX + device.getId();
        setCacheIds(vo.getOpenid(),openIdKey);
        //保存或更新设置的wifi信息
        String id = setWifiService.saveOrUpdateSetWifiInfo(imei,vo);
        log.info("setWifiInfo的id为：{}",id);
        //缓存id
        String idKey = Constant.WIFI_SET_ID_PREFIX+imei;
        //缓存id，应答回了以后根据应答数据更新指令的设置结果
        redisFilterService.setex(idKey,Constant.WIFI_SET_ID_CACHE_TIME, id);
        //发送kafka通知
        JSONObject kafkaJson = new JSONObject();
        kafkaJson.put("name", vo.getName());
        kafkaJson.put("password", vo.getPassword());
        kafkaJson.put("ssid",vo.getSsid());
        kafkaService.emitDeviceDemand(imei, ConstKafka.DEVICE_TYPE_SET_WIFI, kafkaJson, vo.getOpenid());
        return ResponseMap.success();
    }


    /**
     * @description
     * @author cwj
     * @param [imei, vo]
     * @return com.iot08.common.utils.response.ResponseMap
     * @date @time 2024/12/26 9:12
     **/
   /* public ResponseMap addWifiInfo(String imei,DeviceUpdateWifiInfoReqVO vo){
        setWifiService.saveOrUpdateSetWifiInfo(imei,vo);
        return ResponseMap.success();
    }*/


    /**
     * @description 
     * @author cwj
     * @param [imei, vo]
     * @return com.iot08.common.utils.response.ResponseMap
     * @date @time 2024/12/25 18:26
     **/
    public ResponseMap editWifiInfo(DeviceUpdateWifiInfoReqVO vo){
        return setWifiService.updateSetWifiInfo(vo);
    }
    

    /**
     * @description
     * @author cwj
     * @param [imei, vo]
     * @return com.iot08.common.utils.response.ResponseMap
     * @date @time 2024/12/19 17:45
     **/
    public ResponseMap delWifiInfo(String imei, WifiInfoReqVO vo){
        //检查设备是否在线，不在线不能下发
        String onlineStatus = redisClusterService.hget(imei, ConstCacheField.ONLINE_STATUS);
        if (!"1".equals(onlineStatus)) {
            return ResponseMap.fail(ResponseEnum.STATUS5001.getCode(), ResponseEnum.STATUS5001.getMsg());
        }
        /*String key = Constant.WIFI_SEARCH_PREFIX+imei;
        String wifiData = redisFilterService.get(key);
        if(!StringUtils.isEmpty(wifiData)) {
            String[] wifiDatas = wifiData.split(",");
            StringBuilder sb = new StringBuilder();
            for (int i = 0; i < wifiDatas.length - 1; i = i + 2) {
               if(!(vo.getName().equals(wifiDatas[i]) && vo.getSsid().equals(wifiDatas[i+1]))){
                   sb.append(wifiDatas[i]).append(",").append(wifiDatas[i+1]);
                   if(i<wifiDatas.length-2){
                       sb.append(",");
                   }
               }
            }
            redisFilterService.del(key);
            if(ObjectUtils.isNotEmpty(sb)){
                //重新设置WIFI缓存数据
                redisFilterService.setex(key,Constant.WIFI_SEARCH_DATA_CACHE_TIME,sb.toString());
            }
        }*/
        //删除已经设置的WIFI
        //setWifiService.deleteSetWifiByImeiName(imei,vo.getName(),vo.getOpenid());
        setWifiService.delById(new ObjectId(vo.getWId()));
        //发送kafka通知
        JSONObject kafkaJson = new JSONObject();
        kafkaJson.put("name", vo.getName());
        kafkaJson.put("ssid",vo.getSsid());
        kafkaService.emitDeviceDemand(imei, ConstKafka.DEVICE_TYPE_DEL_WIFI, kafkaJson, vo.getOpenid());
        return ResponseMap.success();
    }


    /**
     * @description 查询设备当前连接WIFI
     * @author cwj
     * @param [imei, vo]
     * @return com.iot08.common.utils.response.ResponseMap
     * @date @time 2024/12/20 10:43
     **/
    public ResponseMap queryCurrentWifiInfo(String imei,BaseAccountReqVO vo){
        //检查设备是否在线，不在线不能下发
        String onlineStatus = redisClusterService.hget(imei, ConstCacheField.ONLINE_STATUS);
        if (!"1".equals(onlineStatus)) {
            return ResponseMap.fail(ResponseEnum.STATUS5001.getCode(), ResponseEnum.STATUS5001.getMsg());
        }
        ResponseMap res = ResponseMap.success();
        String key = Constant.WIFI_CURRENT_CONNECT_PREFIX+imei;
        String currentConnectWifi = redisFilterService.get(key);
        if(!StringUtils.isEmpty(currentConnectWifi)){
            String[] connectWifis = currentConnectWifi.split(",");
            res.put("name",connectWifis[0]);
            res.put("ssid",connectWifis[1]);
        }else{
            String openIdKey =  Constant.WIFI_CUR_OPENID_PREFIX + imei;
            //设置指令下发的openid,推送时取出来推送信息
            setCacheIds(vo.getOpenid(), openIdKey);
            kafkaService.emitDeviceDemand(imei, ConstKafka.DEVICE_TYPE_CURRENT_CONNECT_WIFI, new JSONObject(), vo.getOpenid());
            res.put("name","");
            res.put("ssid","");
        }
        return res;
    }

    /**
     * 获取家庭成员
     *
     * @param vo
     * @time: 2021/1/11 14:50
     * @author: Rock
     * @version 1.0
     */
    public ResponseMap getMember(ImeiParamReqVO vo) {
        Device device = this.findById(vo.getImei());
        if (device == null) {
            log.error("Device is null. _id={}", vo.getImei());
            return ResponseMap.fail(ResponseEnum.STATUS2001.getCode(), ResponseEnum.STATUS2001.getMsg(), vo.getImei());
        }
        List<Map<String, Object>> list = new ArrayList<>();
        if (CollectionUtil.isNotEmpty(device.getUserMap())) {
            for (Map.Entry<String, Map<String, Object>> entry : device.getUserMap().entrySet()) {
                Map<String, Object> temp = new HashMap<>();
                temp.put("id", entry.getKey());
                temp.put("relationship", entry.getValue().get("relationship"));
                temp.put("phone", entry.getValue().get("phone"));
                temp.put("time", StringUtil.isNumeric(entry.getValue().get("t")) ? new Double(entry.getValue().get("t").toString()) : 0);
                temp.put("relationship_image_id", entry.getValue().get("relationship_image_id"));
                list.add(temp);
            }
            //根据time降序排序
            CollectionUtil.sortDouble(list, "time", 2);
        }
        ResponseMap data = ResponseMap.success();
        data.put("openid_list", list);
        return data;
    }

    /**
     * 添加家庭成员
     * @param vo
     * @time: 2020/12/2 15:54
     * @author: Rock
     * @version 1.0
     */
    public ResponseMap addMember(DeviceAddMemberReqVO vo) {
        JSONArray openidsJsonArr = JSON.parseArray(vo.getOpenids());
        if (openidsJsonArr != null && openidsJsonArr.size() > 0) {
            ResponseMap data = ResponseMap.success();
            JSONObject openidJson = null;
            Device device = null;
            for (int i = 0; i < openidsJsonArr.size(); i++) {
                openidJson = openidsJsonArr.getJSONObject(i);
                //对应的imei openid关系绑定处理
                String imei = openidJson.getString("imei");
                String openid = openidJson.getString("openid");
                device = this.findById(imei);
                if (device == null) {
                    log.error("Device is null. _id={}", imei);
                    return ResponseMap.fail(ResponseEnum.STATUS2001.getCode(), ResponseEnum.STATUS2001.getMsg(), imei);
                }
                Update updateDevice = new Update();
                //openids处理
                Map<String, Object> openidMap = new HashMap<>();
                openidMap.put("c", vo.getOpenid());
                openidMap.put("relationship", openidJson.get("relationship"));
                openidMap.put("phone", openidJson.get("phone"));
                openidMap.put("relationship_image_id", openidJson.get("relationship_image_id"));
                openidMap.put("t", DateUtil.nowTimestampToDouble());
                Map<String, Map<String, Object>> openidsMap = device.getUserMap();
                if (openidsMap == null) {
                    openidsMap = new HashMap<>();
                    device.setUserMap(openidsMap);
                }


                if (openidsMap.size() < Constant.DEVICE_OPENID_NUM) {
                    openidsMap.put(openid, openidMap);
                } else {
                    log.error("号码数量不能超过{}个 imei:{}", Constant.DEVICE_OPENID_NUM, imei);
                    return ResponseMap.fail(ResponseEnum.STATUS4010.getCode(),"API.request.contantNumLimit", Constant.DEVICE_OPENID_NUM);
                }
                updateDevice.set("u", openidsMap);
                //更新操作
                this.updateById(imei, updateDevice);
                data.put("id", openid);
            }
            return data;
        }
        return ResponseMap.fail(ResponseEnum.STATUS400.getMsg());
    }

    /**
     * 修改家庭成员
     *
     * @param vo
     * @time: 2020/12/2 18:24
     * @author: Rock
     * @version 1.0
     */
    public ResponseMap updateMember(DeviceUpdateMemberReqVO vo) {
        Device device = this.findById(vo.getImei());
        if (device == null || device.getUserMap() == null) {
            log.error("Device or UserMaps is null. _id={}, device={}", vo.getImei(), device);
            return ResponseMap.fail();
        }
        if (device.getCheckedOpenidsMap() == null) {
            device.setCheckedOpenidsMap(new HashMap<>());
        }
        if (!CollectionUtil.containsKey(device.getUserMap(), vo.getId())) {
            return ResponseMap.fail(ResponseEnum.STATUS4006.getCode(), "API.request.parameterError");
        }
        UpdateVO update = new UpdateVO();
        Map<String, Object> userSub = device.getUserMap().get(vo.getId());
        Long time = DateUtil.nowTimestampToLong();
        userSub.put("t", time);
        if (!userSub.containsKey("c")) {
            userSub.put("c", vo.getOpenid());
        }
        if (StringUtil.isNotBlank(vo.getRelationship())) {
            userSub.put("relationship", vo.getRelationship());
        }
        if (StringUtil.isNotBlank(vo.getPhone())) {
            userSub.put("phone", vo.getPhone());
        }
        if (StringUtil.isNotBlank(vo.getRelationship_image_id())) {
            userSub.put("relationship_image_id", Integer.valueOf(vo.getRelationship_image_id()));
        }
        //设置更新 家庭成员
        device.getUserMap().put(vo.getId(), userSub);
        update.setMap("u", device.getUserMap());
        if (CollectionUtil.containsKey(device.getCheckedOpenidsMap(), vo.getId())) {
            device.getCheckedOpenidsMap().put(vo.getId(), userSub);
            update.setMap("checked_openids", device.getCheckedOpenidsMap());
        }

        this.updateById(vo.getImei(), update);

        //更新一下 下发给手表的 通信录 (16指令)
        JSONObject kafkaJson = new JSONObject();
        //handleFlag  1:添加 2:删除 3:修改
        kafkaJson.put("handleFlag", 2);
        kafkaService.emitDeviceDemand(device.getId(), ConstKafka.DEVICE_TYPE_Contact, kafkaJson, vo.getOpenid());

        return ResponseMap.success();
    }

    /**
     * 删除家庭成员
     *
     * @param vo
     * @time: 2020/12/4 9:29
     * @author: Rock
     * @version 1.0
     */
    public ResponseMap delMember(DeviceDelMemberReqVO vo) {
        //如果是openid 和 id 相等, 那么代表是解绑或者是注销账号等自我操作, 不发推送
        boolean isSelf = false;
        if(vo.getId().equals(vo.getOpenid())){
            log.info("openid 和 id 相等, 那么代表是解绑或者是注销账号等自我操作, 不发推送 vo:{}", vo.toString());
            isSelf = true;
        }
        //当前这个Dev 要删除家庭成员
        Device device = this.findById(vo.getImei());
        if (device == null) {
            log.error("Device is null. _id={}", vo.getImei());
            return ResponseMap.fail(ResponseEnum.STATUS2001.getCode(), ResponseEnum.STATUS2001.getMsg(), vo.getImei());
        }
//        //token检查
//        String token = redisClusterService.hget(vo.getImei(), ConstCacheField.TOKEN);
//        if (StringUtil.isBlank(token) || !token.equals(vo.getAuthcode())) {
//            return ResponseMap.fail(ResponseEnum.STATUS403.getCode(), "API.request.deviceCodeInactive");
//        }
        // 赛诺的注释掉这个不然和 通讯录删除联系人 冲突
//        //频繁操作的 openid 检查
//        if (StringUtil.isNotBlank(redisClusterService.get(CacheEnum.FREQUENT.getKey() + vo.getImei()))) {
//            return ResponseMap.fail(ResponseEnum.STATUS500.getCode(), "API.request.frequentOperationError");
//        } else {
//            //设置操作标识
//            redisClusterService.setex(CacheEnum.FREQUENT.getKey() + vo.getImei(), CacheEnum.FREQUENT.getExpire(), vo.getOpenid());
//        }
        if (!CollectionUtil.containsKey(device.getUserMap(), vo.getId())) {
            return ResponseMap.fail(ResponseEnum.STATUS4006.getCode(), "API.request.parameterError");
        }
        //找到要 删除的家庭成员的 Account 对象
        String openId = vo.getId();
        Account account = accountService.findById(openId);
        if (account == null) {
            log.error("Account is null. _id={}", openId);
            return ResponseMap.fail(ResponseEnum.STATUS2000.getCode(), ResponseEnum.STATUS2000.getMsg());
        }
        JSONObject pushData = new JSONObject();
        JSONObject pushDataSub = new JSONObject();
        String deviceName = this.getDeviceName(device);
        // 【%s】手表【%s】的管理员取消您关注手表  API.request.adminUnbindDevice
        String msgTitle = MessageUtils.getLocale("API.request.adminUnbindDevice", deviceName, vo.getImei());

        pushDataSub.put("imei", vo.getImei());
        pushDataSub.put("timestamp", DateUtil.nowTimestampToDouble());
        pushDataSub.put("type", "unbind");
        pushDataSub.put("name", deviceName);
        pushDataSub.put("msgTitle", msgTitle);
        pushDataSub.put("msgContent", msgTitle);
        pushData.put("type", ConstKafka.ACCOUNT_MESSAGE);
        pushData.put("message", pushDataSub);

        UpdateVO updateDevice = new UpdateVO();

        UpdateVO updateAccount = new UpdateVO();

        //解除设备关联
//        Set<String> delKey = new HashSet<>();
//        for (Map.Entry<String, Map<String, Object>> entry : device.getUserMap().entrySet()) {
//            if (account.getId().equals(entry.getValue().get("c"))) {
//                delKey.add(entry.getKey());
//            }
//        }
//        if (delKey.size() > 0) {
//
////                CollectionUtil.removeMapKeys(device.getUserMap(), delKey);
////                updateDevice.setMap("u", device.getUserMap());
//            CollectionUtil.removeMapKeys(device.getCheckedOpenidsMap(), delKey);
//            updateDevice.setMap("checked_openids", device.getCheckedOpenidsMap());
//        }
//
        //清除可视频联系人及微聊联系人的列表
        if (CollectionUtil.removeMapKey(device.getCheckedOpenidsMap(), account.getId())) {
            updateDevice.setMap("checked_openids", device.getCheckedOpenidsMap());
            //如果具有短标识 三基的设备, 需要更新视频联系人
            if (device.getModules().contains(ConstVideo.V0JF)) {
                // 有菊风视频
                String shortId = RedisClusterService.getJedisCluster().hget(device.getId(), "shortId");
                if (StringUtils.isNotBlank(shortId)) {
                    //查询设备的微聊联系人，存在则下发删除微聊联系人的指令
                    if(ObjectUtils.isNotEmpty(device.getIsNewWechatProtocol()) && device.getIsNewWechatProtocol().equals(1) && StringUtils.isNotEmpty(account.getPhone())) {
                        WechatContact wechatContact = wechatContactService.queryByImePhone(device.getId(),account.getPhone());
                        if(ObjectUtils.isNotEmpty(wechatContact)) {
                            JSONObject kafkaJson = new JSONObject();
                           // kafkaJson.put("phone", wechatContact.getPhone());
                            kafkaJson.put("openId", wechatContact.getOpenid());
                            //下发删除指令
                            kafkaService.emitDeviceDemand(device.getId(), ConstKafka.DEVICE_TYPE_DEL_NEW_CONTACT, kafkaJson, vo.getOpenid());
                            //删除单个微聊联系人记录
                            wechatContactService.delById(new ObjectId(wechatContact.getId()));
                        }
                    } else {
                        //三基的短标识设备
                        JSONObject kafkaJson = new JSONObject();
                        kafkaJson.put("openid", account.getId());
                        kafkaService.emitDeviceDemand(device.getId(), ConstKafka.DEVICE_TYPE_DownDelVideoContact, kafkaJson, null);
                    }
                }
            }
        }
        //TODO 这里要暂时兼容Python 版本的 ,删除家庭成员(删除通讯录中的成员)清除通讯录中的对应的openid的联系人
        if (device.getContactMap() != null && device.getContactMap().size() > 0) {
            //迭代器移除
            Iterator<Map.Entry<String, Map<String, Object>>> contactMapIt = device.getContactMap().entrySet().iterator();
            boolean needUpdate = false;
            while (contactMapIt.hasNext()){
                Map.Entry<String, Map<String, Object>> nextItem = contactMapIt.next();
                JSONObject item = new JSONObject(nextItem.getValue());
                if (item.containsKey("openid") && openId.equals(item.getString("openid"))) {
                    log.info("imei:{} 这里要暂时兼容Python 版本的 ,删除家庭成员(删除通讯录中的成员)清除通讯录中的对应的openid的联系人: {}", vo.getImei(), openId);
                    contactMapIt.remove();
                    needUpdate = true;
                }
            }
            if (needUpdate) {
                updateDevice.setMap("c", device.getContactMap());
            }
        }

        //清除Account 表中的 d 字段
        if (CollectionUtil.removeMapKey(account.getDeviceMap(), vo.getImei())) {
            updateAccount.setMap("d", account.getDeviceMap());
        }
        //清除Device 表中的 u 字段 中的这个account 账号对应 u
        Map<String, Object> removeUser = CollectionUtil.removeMapKeyData(device.getUserMap(), account.getId());
        if (removeUser != null) {
            updateDevice.setMap("u", device.getUserMap());
        }
        if (CollectionUtil.isNotEmpty(device.getUserMap())) {
            //将设备从与该用户关联的群组中移出
            if (removeUser != null && StringUtil.isNotBlank(removeUser.get("g")) && ObjectId.isValid(removeUser.get("g").toString())) {
                ChatGroup chatGroup = chatGroupService.findById(new ObjectId(removeUser.get("g").toString()));
                if (chatGroup != null) {
                    if (CollectionUtil.removeMapKey(chatGroup.getMemberMap(), account.getId())) {
                        chatGroupService.updateById(new ObjectId(chatGroup.getId()), new UpdateVO().setMap("m", chatGroup.getMemberMap()));
                        if(!isSelf && vo.getCallType() != 1){
                            //发送kafka
//                            JSONObject push_CHAT_GROUP_REMOVE_extOb = new JSONObject();
//                            push_CHAT_GROUP_REMOVE_extOb.put("operator", openId);
//                            push_CHAT_GROUP_REMOVE_extOb.put("openid", openId);
//                            push_CHAT_GROUP_REMOVE_extOb.put("disbandTime", DateUtil.nowTimestampToLong());
//                            // 【%s】的%s取消关注手表 API.pushTitle.unfollowDevNotification
//                            String title = MessageUtils.getLocale("API.pushTitle.unfollowDevNotification", deviceName, relationship);
//                            push_CHAT_GROUP_REMOVE_extOb.put("msgTitle", title);
//                            push_CHAT_GROUP_REMOVE_extOb.put("name", deviceName);
//                            push_CHAT_GROUP_REMOVE_extOb.put("imei", vo.getImei());
                            kafkaService.sendPushToChatGroup(chatGroup, account, ConstKafka.CHAT_GROUP_REMOVE, account.getId(), null);
                        }

                    }
                    if (CollectionUtil.removeMapKey(account.getChatGroupMap(), chatGroup.getId())) {
                        updateAccount.set("g", account.getChatGroupMap());
                        updateAccount.unset(chatGroup.getId());
                    }
                }
            }
        } else {
            //将没有所有者的设备 移出所有聊天群
            List<ChatGroup> chatGroupList = chatGroupService.listByIds(CollectionUtil.stringToObjectId(device.getChatGroupMap().keySet()));
            for (ChatGroup chatGroup : chatGroupList) {
                if (CollectionUtil.removeMapKey(chatGroup.getDeviceMap(), vo.getImei())) {
                    if (CollectionUtil.isNotEmpty(chatGroup.getDeviceMap())) {
                        chatGroupService.updateById(new ObjectId(chatGroup.getId()), new Update().set("d", chatGroup.getDeviceMap()));
                    } else {
                        chatGroupService.delById(new ObjectId(chatGroup.getId()));
                        if(!isSelf){
                            //发送kafka
                            JSONObject push_CHAT_GROUP_DISBAND_extOb = new JSONObject();
                            push_CHAT_GROUP_DISBAND_extOb.put("operator", openId);
                            push_CHAT_GROUP_DISBAND_extOb.put("openid", openId);
                            push_CHAT_GROUP_DISBAND_extOb.put("disbandTime", DateUtil.nowTimestampToLong());
                            // 手表【%s】的管理员将手表恢复出厂设置
                            String title = MessageUtils.getLocale("API.pushTitle.adminResetDevNotification", deviceName);
                            log.info("-----------------title---------------:"+title);
                            push_CHAT_GROUP_DISBAND_extOb.put("msgTitle", title);
                            push_CHAT_GROUP_DISBAND_extOb.put("name", deviceName);
                            push_CHAT_GROUP_DISBAND_extOb.put("imei", vo.getImei());
                            kafkaService.sendPushToChatGroup(chatGroup, null, ConstKafka.CHAT_GROUP_DISBAND, vo.getOpenid(), push_CHAT_GROUP_DISBAND_extOb);
                        }
                    }
                }
                if (CollectionUtil.removeMapKey(device.getChatGroupMap(), chatGroup.getId())) {
                    updateDevice.setMap("g", device.getChatGroupMap());
                }
                if (CollectionUtil.removeMapKey(account.getChatGroupMap(), chatGroup.getId())) {
                    updateAccount.setMap("g", account.getChatGroupMap());
                    updateAccount.unset(chatGroup.getId());
                }
            }
        }

        //删除家庭成员推送
        if (new Integer(4).equals(account.getWxgzIdent())) {
            //当前微信公众号创建的账号绑定的imei
            if (vo.getImei().equals(account.getWxgzChatImei())) {
                //删除的是 微信公众号创建的账号绑定的imei
                if (CollectionUtil.isNotEmpty(account.getDeviceMap())) {
                    if (account.getDeviceMap().size() == 1) {
                        updateAccount.unset("wxgz_chat_imei");
                    }
                    for (String key : account.getDeviceMap().keySet()) {
                        if (!key.equals(account.getWxgzChatImei())) {
                            updateAccount.set("wxgz_chat_imei", key);
                        }
                    }
                }
            }
            String content = MessageUtils.getLocale("API.pushTitle.delMemberNotification",
                    getDeviceName(device));
            boolean send = weixinService.replyWxMsg(Constant.WEIXIN_PUSH_TYPE_1, content, account.getWxgzMasterId(), account.getWxid());
            if (!send) {
                log.error("删除家庭成员推送失败,imei:{}", account.getWxgzChatImei());
            }
        }
        //推送
        if(!isSelf){
            kafkaService.sendPushToAccount(ConstKafka.ACCOUNT_TYPE_3, openId, pushData);
        }
        //if(ObjectUtils.isEmpty(device.getIsNewWechatProtocol()) || !device.getIsNewWechatProtocol().equals(1)) {
        //检查家庭成员和联系人是否存在，不存在则，按照之前业务发送指令的顺序生成序列号
        if(isSerialNumNull(device)) {
            //更新设备绑定人（家庭成员的编号）,删除了当前家庭成员的用户
            int index = updateDeviceUserSerialNo(device,device.getUserMap(), updateDevice);
            //更新设备联系人的编号
            updeteDeviceContactSerialNo(device,device.getContactMap(), index, updateDevice);
        }
        //更新操作,无编号则更新编号，删除这个联系人
        this.updateById(device.getId(), updateDevice);
        accountService.updateById(account.getId(), updateAccount);
        if (removeUser != null) {
            //删除image文件.是整数则为系统的图片，不能删除
            if (StringUtil.isNotBlank(removeUser.get("image")) && !StringTool.isInteger(removeUser.get("image").toString())) {
                //删除文件
                baseBucketTool.delFile(BaseBucketTool.CONTACT_COMMON_PATH + removeUser.get("image").toString());
            }
            if(ObjectUtils.isNotEmpty(removeUser.get("serialNum"))) {
                JSONObject kafkaJson = new JSONObject();
                kafkaJson.put("serialNum",removeUser.get("serialNum").toString());
                //下发删除指令
                kafkaService.emitDeviceDemand(device.getId(), ConstKafka.DEVICE_TYPE_DEL_CONTACT, kafkaJson, vo.getOpenid());
                //更新设备联系人的最大编号的缓存
                updateCacheMaxSerialNum(device);
            } else {
                return ResponseMap.fail(ResponseEnum.STATUS400.getCode(),"被删除的联系人编号不存在，无法删除");
            }
        }
        //更新一下 下发给手表的 通信录 (16指令)
        /*JSONObject kafkaJson = new JSONObject();
        //handleFlag  1:添加 2:删除 3:修改
        kafkaJson.put("handleFlag", 3);
        kafkaService.emitDeviceDemand(device.getId(), ConstKafka.DEVICE_TYPE_Contact, kafkaJson, vo.getOpenid());*/
        return ResponseMap.success();

    }

    /**
     * 获取设备可视频的成员列表
     *
     * @param imei
     * @time: 2020/12/3 16:10
     * @author: Rock
     * @version 1.0
     */
    public ResponseMap getOpenidList(String imei) {
        Device device = this.findById(imei);
        if (device == null) {
            log.error("Device is null. _id={}", imei);
            return ResponseMap.fail(ResponseEnum.STATUS2001.getCode(), ResponseEnum.STATUS2001.getMsg(), imei);
        }
        //TODO 为了兼容 Python => Java 的衔接,需要读取 通讯录中之前存的管理员和 canVideo==1 的成员 加到 CheckedOpenidsMap(可视频的成员列表)中去
        // 只是临时的
        if (device.getCheckedOpenidsMap() == null) {
            device.setCheckedOpenidsMap(new HashMap<>());
        }
        boolean needUpdate = false;
        for (Map.Entry<String, Map<String, Object>> entry: device.getContactMap().entrySet()) {
            JSONObject temp = new JSONObject(entry.getValue());
            if (temp.containsKey("openid")) {
                if (temp.getInteger("canVideo") != null && 1 == temp.getInteger("canVideo") ) {
                    if (!device.getCheckedOpenidsMap().containsKey(temp.getString("openid"))) {
                        /*
                        "a1f46bc0" : {
                                "openid" : "e397b89d0ec7344b76b71e25",
                                "c" : "e397b89d0ec7344b76b71e25",
                                "name" : "爸爸",
                                "image" : "1",
                                "phone" : "18320032857",
                                "t" : 1624085147.151177,
                                "canVideo" : 1,
                                "identity" : "admin"
                        },
                        "884a8738" : {
                                "openid" : "b2f2a075172814dd2f7241ed",
                                "c" : "b2f2a075172814dd2f7241ed",
                                "name" : "jj",
                                "image" : "9",
                                "phone" : "13202003459",
                                "t" : 1624086980.442964,
                                "identity" : "member"
                        }
                        */
                        //没有对应的openid的添加进去
                        String openid = temp.getString("openid");
                        Map<String, Object> sub = new HashMap<>();
                        sub.put("openid", openid);
                        sub.put("c", openid);
                        sub.put("relationship", temp.get("relationship"));
                        sub.put("relationship_image_id", temp.get("relationship_image_id"));
                        sub.put("t", temp.get("t"));
                        sub.put("identity", temp.get("identity"));
                        device.getCheckedOpenidsMap().put(openid, sub);
                        needUpdate = true;
                    }
                }
            }
        }
        if(needUpdate){
            //保存一下
            this.updateById(imei, new Update().set("checked_openids", device.getCheckedOpenidsMap()));
        }

        //----------------
        List<Map<String, Object>> checkedOpenidList = new ArrayList<>();
        List<Map<String, Object>> uncheckedOpenidList = new ArrayList<>();
        if (CollectionUtil.isNotEmpty(device.getUserMap())) {
            if (CollectionUtil.isNotEmpty(device.getCheckedOpenidsMap())) {
                for (String key : device.getCheckedOpenidsMap().keySet()) {
                    if (device.getUserMap() != null) {
                        if(device.getUserMap().get(key) == null){
                            log.error("imei:{} checkedOpenids :{} 和 家庭成员u :{} 对应不上 key", imei, device.getCheckedOpenidsMap() ,device.getUserMap());
                            continue;
                        }
                        //可视频成员
                        JSONObject temp = new JSONObject(device.getUserMap().get(key));
                        if (temp != null) {
                            temp.put("id", key);
                            temp.put("openid", key);
                            temp.put("time", temp.getDouble("t").longValue());
                            //TODO 这里是做一下补偿,是 Python 切换成Java 的后遗症 (后续要移除此操作) 下面的也是
                            if (!temp.containsKey("relationship")){
                                //调用一下获取通讯录的接口, 兼容处理一下联系人关系等.
                                this.getContact(imei);
                                temp.put("relationship", "");
                                temp.put("relationship_image_id", 9);
                            }
                            temp.remove("c");
                            temp.remove("t");
                            checkedOpenidList.add(temp);
                        }
                    }
                }

                //最后一步删除，下个for循环用到
                device.getUserMap().keySet().removeAll(device.getCheckedOpenidsMap().keySet());
            }
            for (Map.Entry<String, Map<String, Object>> entry : device.getUserMap().entrySet()) {
                if (!entry.getKey().contains("wx_")) {
                    //如果是微信公众号的成员 不能使用视频通话 (APP获取时去掉) 微信公众号的成员openid 是带前缀 wx_ 的
                    JSONObject temp = new JSONObject(entry.getValue());
                    String openid = entry.getKey();
                    if (temp != null) {
                        temp.put("id", openid);
                        temp.put("openid", openid);
                        temp.put("time", temp.getDouble("t").longValue());
                        if (!temp.containsKey("relationship")){
                            temp.put("relationship", "");
                            temp.put("relationship_image_id", 9);
                        }
                        temp.remove("c");
                        temp.remove("t");
                        uncheckedOpenidList.add(temp);
                    }
                }
            }
        }


        ResponseMap data = ResponseMap.success();
        //根据time降序排序
        CollectionUtil.sortDouble(checkedOpenidList, "time", 2);
        CollectionUtil.sortDouble(uncheckedOpenidList, "time", 2);
        data.put("checked_video_list", checkedOpenidList);
        data.put("unchecked_video_list", uncheckedOpenidList);
        return data;
    }

    /**
     * 添加设备可视频成员列表
     *
     * @param imei
     * @param vo
     * @time: 2020/12/4 9:31
     * @author: Rock
     * @version 1.0
     */
    public ResponseMap addOpenidList(String imei, DeviceAddOpenidListReqVO vo) {
        Device device = this.findById(imei);
        if (device == null) {
            log.error("Device is null. _id={}", imei);
            return ResponseMap.fail(ResponseEnum.STATUS2001.getCode(), ResponseEnum.STATUS2001.getMsg(), imei);
        }
        if (CollectionUtil.isNotEmpty(device.getUserMap())) {
            UpdateVO update = new UpdateVO();
            JSONArray openidsJson = JSON.parseArray(vo.getOpenids());
            boolean isSJ_JFDev = false;
            if (device.getModules().contains(ConstVideo.V0JF)) {
                // 有菊风视频
                String shortId = RedisClusterService.getJedisCluster().hget(device.getId(), "shortId");
                if (StringUtils.isNotBlank(shortId)) {
                    //三基的短标识设备
                    isSJ_JFDev = true;
                }
            }
            for (int i = 0; i < openidsJson.size(); i++) {
                String openid = openidsJson.getString(i);
                if (device.getUserMap().containsKey(openid)) {
                    Map<String, Object> item = new HashMap<>();
                    item.put("openid", openid);
                    item.put("c", openid);
                    item.put("relationship", device.getUserMap().get(openid).get("relationship"));
                    item.put("phone", device.getUserMap().get(openid).get("phone"));
                    item.put("relationship_image_id", device.getUserMap().get(openid).get("relationship_image_id"));
                    item.put("t", DateUtil.nowTimestampToDouble());
                    if(device.getUserMap().get(openid).get("identity") != null){
                        item.put("identity", device.getUserMap().get(openid).get("identity"));
                    }
                    if (device.getCheckedOpenidsMap() == null) {
                        device.setCheckedOpenidsMap(new HashMap<>());
                    } else if (device.getCheckedOpenidsMap().size() >= Constant.DEVICE_OPENID_NUM) {
                        log.error("号码数量不能超过{}个={}", Constant.DEVICE_OPENID_NUM, imei);
                        return ResponseMap.fail(ResponseEnum.STATUS4010.getCode(), "API.request.contantNumLimit", Constant.DEVICE_OPENID_NUM);
                    }
                    device.getCheckedOpenidsMap().put(openid, item);

                    //三基的短标识设备 需要更新视频联系人
                    if(isSJ_JFDev){
                        try{
                            JSONObject kafkaJson = new JSONObject();
                            if(!ObjectUtils.isEmpty(device.getIsNewWechatProtocol()) && device.getIsNewWechatProtocol().equals(1)){
                                Account account = accountService.findById(openid);
                                if(ObjectUtils.isNotEmpty(account)) {
                                    kafkaJson.put("name",device.getUserMap().get(openid).get("relationship"));
                                    kafkaJson.put("phone",account.getPhone());
                                    String wechatAvator = "";
                                    //没有上传图像则用旧图像，旧图像不存在或是默认图像则没有图像，暂时不发头像，没搞清楚协议中图像数据的发送的编码
                                    if (StringUtil.isNotBlank(account.getImage()) && !account.getImage().contains("default.jpg")){
                                        wechatAvator =  BaseBucketTool.ACCOUNT_COMMON_PATH + account.getImage();
                                        if(!"ASR".equals(device.getPlatform())) {
                                            kafkaJson.put("avator", "/" + wechatAvator);
                                        }
                                    }
                                    log.info("新版协议添加微聊联系人及视频联系人的指令，指令数据为：{}",kafkaJson);
                                    //发送视频微聊联系人指令
                                    kafkaService.emitDeviceDemand(device.getId(), ConstKafka.DEVICE_TYPE_ADD_NEW_CONTACT, kafkaJson, vo.getOpenid());
                                    //创建单聊组，加入群聊组
                                    //群聊的创建与绑定，取群组，没有群组则创建群组
                                    ChatGroup chatGroup = chatGroupService.getChatGroupByDeviceG(device.getChatGroupMap(), vo.getOpenid());
                                    UpdateVO accountUpdate = new UpdateVO();
                                    //用户绑定上设备 ==> "d" 字段 (deviceMap)，添加用户绑定的设备信息
                                    AddRelatedDeviceReqBodyFormVO bodyFormVo = new AddRelatedDeviceReqBodyFormVO();
                                    bodyFormVo.setRelationship(device.getUserMap().get(openid).get("relationship").toString());
                                    bodyFormVo.setRelationship_image_id(Integer.valueOf(device.getUserMap().get(openid).get("relationship_image_id").toString()));
                                    accountService.addDeviceHandle(account, chatGroup.getId(), device, accountUpdate, bodyFormVo);
                                    //用户绑定上群组 ==> "g" 字段 (chatGroupMap)，添加
                                    accountService.addChatGroupHandle(account, chatGroup.getId(), accountUpdate);
                                    //多人群组的绑定
                                    UpdateVO chatGroupUpdate = new UpdateVO();
                                    //更新群组的member信息
                                    chatGroupService.addAccountHandle(chatGroup, account.getId(), chatGroupUpdate);
                                    //更新群组的device信息
                                    chatGroupService.addDeviceHandle(chatGroup, device.getId(), device.getVendor(), chatGroupUpdate);
                                    //单聊群组创建和绑定，单聊群组用用户openid+"&"+imei做id来关联用户和设备
                                    singleChatGroupService.createSingleG(account.getId(), device.getId());
                                    UpdateVO deviceUpdate = new UpdateVO();
                                    if (device.getChatGroupMap() == null) {
                                        device.setChatGroupMap(new HashMap<>());
                                    }
                                    Map<String, Object> sub = new HashMap<>();
                                    sub.put("t", System.currentTimeMillis() / 1000d);
                                    device.getChatGroupMap().put(chatGroup.getId(), sub);
                                    deviceUpdate.setMap("g", device.getChatGroupMap());
                                    //增加device的g字段信息，更新设备群聊组的信息
                                    this.addChatGroupHandle(device, chatGroup.getId(), deviceUpdate);
                                    //保存或更新微聊联系人，保存数据时存全路径
                                    wechatContactService.saveOrUpdateWechatContact(device.getId(),account.getPhone(),account.getId(),chatGroup.getId(),
                                            device.getUserMap().get(openid).get("relationship").toString(),
                                            StringUtils.isNotEmpty(wechatAvator) ? (baseBucketTool.getDOMAIN() + wechatAvator):wechatAvator);
                                }
                            } else {
                                kafkaJson.put("openid", openid);
                                kafkaJson.put("phone", item.get("phone"));
                                kafkaJson.put("name", item.get("relationship"));
                                kafkaJson.put("relationship", item.get("relationship"));
                                kafkaJson.put("relationship_image_id", item.get("relationship_image_id"));
                                kafkaService.emitDeviceDemand(device.getId(), ConstKafka.DEVICE_TYPE_DownAddVideoContact, kafkaJson, null);
                            }
                        }catch (Exception e){
                            log.error("imei:"+imei+" 添加 视频成员时, 下发kafka消息错误:"+e.getMessage(), e);
                        }
                    }

                } else {
                    log.error("imei:%s 添加 openid 时成员不在绑定的关系里面 notFoundOpenid: %s ", imei, openid);
                }
            }
            update.setMap("checked_openids", device.getCheckedOpenidsMap());
            this.updateById(device.getId(), update);
        }
        return ResponseMap.success();
    }

    /**
     * 删除设备可视频成员列表
     *
     * @param imei
     * @param vo
     * @time: 2020/12/3 19:05
     * @author: Rock
     * @version 1.0
     */
    public ResponseMap delOpenidList(String imei, DeviceAddOpenidListReqVO vo) {
        //删除设备可视频成员列表，只有管理员身份才可以修改
        if(!accountService.checkAccountIsAdminWithImei(vo.getOpenid(), imei)){
            //仅限于管理员操作  API.request.onlyAdminOperation
            return ResponseMap.fail(ResponseEnum.STATUS403.getCode(), "API.request.onlyAdminOperation");
        }
        Device device = findById(imei);
        if (device == null) {
            log.error("Device is null. _id={}", imei);
            return ResponseMap.fail(ResponseEnum.STATUS2001.getCode(), ResponseEnum.STATUS2001.getMsg(), imei);
        }
        boolean isSJ_JFDev = false;
        if (device.getModules().contains(ConstVideo.V0JF)) {
            // 有菊风视频
            String shortId = RedisClusterService.getJedisCluster().hget(device.getId(), "shortId");
            if (StringUtils.isNotBlank(shortId)) {
                //三基的短标识设备
                isSJ_JFDev = true;
            }
        }
        UpdateVO update = new UpdateVO();
        JSONArray openidsJson = JSON.parseArray(vo.getOpenids());
        if (CollectionUtil.isNotEmpty(device.getCheckedOpenidsMap())) {
            for (int i = 0; i < openidsJson.size(); i++) {
                String itemOpenid = openidsJson.getString(i);
                //三基的短标识设备 需要删除视频联系人
                if(isSJ_JFDev){
                    try{
                        if(!ObjectUtils.isEmpty(device.getIsNewWechatProtocol()) && device.getIsNewWechatProtocol().equals(1)) {
                            DeviceWechatContactDelReqVO deviceWechatContactDelReqVo = new DeviceWechatContactDelReqVO();
                            deviceWechatContactDelReqVo.setDeletedOpenid(itemOpenid);
                            deviceWechatContactDelReqVo.setOpenid(vo.getOpenid());
                            //删除新版微聊的数据，解绑设备信息
                            wechatContactService.deleteWechatContact(imei,deviceWechatContactDelReqVo);
                            return ResponseMap.success();
                        } else {
                            JSONObject kafkaJson = new JSONObject();
                            kafkaJson.put("openid", itemOpenid);
                            kafkaService.emitDeviceDemand(device.getId(), ConstKafka.DEVICE_TYPE_DownDelVideoContact, kafkaJson, null);
                            CollectionUtil.removeMapKey(device.getCheckedOpenidsMap(), itemOpenid);
                        }
                    }catch (Exception e){
                        log.error("imei:"+imei+" 删除 视频成员时, 下发kafka消息错误:"+e.getMessage(), e);
                    }
                } else {
                    CollectionUtil.removeMapKey(device.getCheckedOpenidsMap(), itemOpenid);
                }
            }
        }
        update.setMap("checked_openids", device.getCheckedOpenidsMap());

        //TODO 兼容一下 Python 的,防止要切换回去
        boolean needUpdate = false;
        for ( Map.Entry<String, Map<String, Object>> entry : device.getContactMap().entrySet() ) {
            JSONObject temp = new JSONObject(entry.getValue());
            if(temp.containsKey("openid") && temp.containsKey("canVideo") && 1 == temp.getInteger("canVideo")){
                for (int i = 0; i < openidsJson.size(); i++) {
                    String itemOpenid = openidsJson.getString(i);
                    if (itemOpenid.equals(temp.getString("openid"))) {
                        log.info("imei:{} 删除可视频对象联系人 openid:{} 设置canVideo=0",imei, itemOpenid);
                        entry.getValue().put("canVideo", 0);
                        needUpdate = true;
                    }
                }
            }
        }
        if (needUpdate) {
            update.setMap("c", device.getContactMap());
        }

        this.updateById(device.getId(), update);
        return ResponseMap.success();
    }

    /**
     * 更新设备可视频成员列表
     *
     * @param imei
     * @param vo
     * @time: 2020/12/4 10:06
     * @author: Rock
     * @version 1.0
     */
    public ResponseMap updateOpenidList(String imei, DeviceUpdateOpenidListReqVO vo) {
        //更新设备可视频成员列表，只有管理员身份才可以修改
        if(!accountService.checkAccountIsAdminWithImei(vo.getOpenid(), imei)){
            //仅限于管理员操作  API.request.onlyAdminOperation
            return ResponseMap.fail(ResponseEnum.STATUS403.getCode(), "API.request.onlyAdminOperation");
        }
        Device device = this.findById(imei);
        if (device == null) {
            log.error("Device is null. _id={}", imei);
            return ResponseMap.fail(ResponseEnum.STATUS2001.getCode(), ResponseEnum.STATUS2001.getMsg(), imei);
        }
        UpdateVO update = new UpdateVO();
        Map<String, Object> userItem = CollectionUtil.removeMapKeyData(device.getUserMap(), vo.getOld_openid());
        if (userItem != null) {
            userItem.put("openid", vo.getNew_openid());
            device.getUserMap().put(vo.getNew_openid(), userItem);
            update.setMap("u", device.getUserMap());
        }
        userItem = CollectionUtil.removeMapKeyData(device.getCheckedOpenidsMap(), vo.getOld_openid());
        if (userItem != null) {
            userItem.put("openid", vo.getNew_openid());
            device.getCheckedOpenidsMap().put(vo.getNew_openid(), userItem);
            update.setMap("checked_openids", device.getCheckedOpenidsMap());
        }
        this.updateById(imei, update);
        return ResponseMap.success();
    }

    /**
     * 获取通讯录
     *
     * @param imei
     * @time: 2020/12/4 10:08
     * @author: Rock
     * @version 1.0
     */
    public ResponseMap getContact(String imei) {
        Device device = this.findById(imei);
        if (device == null) {
            log.error("Device is null. _id={}", imei);
            return ResponseMap.fail(ResponseEnum.STATUS2001.getCode(), ResponseEnum.STATUS2001.getMsg(), imei);
        }
        ResponseMap data = ResponseMap.success();
        data.put("isIOTCard", device.getIsIOTCard());
        Map<String, Map<String, Object>> contactMap = device.getContactMap();
        //TODO 判断设备是否是物联网卡
        if(device.getWatchCustomFunction() != null && 1 == device.getIsIOTCard() && device.getWatchCustomFunction().contains("IOTCard:RJ")){
            IotCardInfo iotCardInfo = iotCardInfoService.findById(device.getIccid());
            //使用物联网卡记录的 通讯录
            contactMap = iotCardInfo.getContactMap();
        }

        List<Map<String, Object>> whiteContacts = new ArrayList<>();
        List<Map<String, Object>> openid_list = new ArrayList<>();
        boolean needUpdate = false;
        if (CollectionUtil.isNotEmpty(device.getUserMap())) {
            for (String key : device.getUserMap().keySet()) {
                Map<String, Object> tempMap = new HashMap<>();
                JSONObject item = new JSONObject(device.getUserMap().get(key));
                tempMap.put("id", key);
                tempMap.put("time", StringUtil.isNumeric(item.get("t")) ? item.getDouble("t").longValue() : 0);
                //用户联系人给 默认 "member" 成员
                tempMap.put("identity",item.getOrDefault("identity", "member"));
                tempMap.put("type", 1);
                tempMap.put("openid", key);
                Account tempAccount = accountService.findById(key);
                tempMap.put("avator", baseBucketTool.getDOMAIN() + BaseBucketTool.ACCOUNT_COMMON_PATH
                        + (StringUtil.isBlank(tempAccount.getImage()) ? Const.DEFAULT_JPG : tempAccount.getImage()));
                if(item.get("relationship") == null || item.get("phone") == null || item.get("relationship_image_id") == null ){
                    JSONObject acount_D_map = new JSONObject(tempAccount.getDeviceMap().get(imei));
                    tempMap.put("name", acount_D_map.getString("relationship"));
                    tempMap.put("phone", acount_D_map.getString("my_phone"));
                    tempMap.put("relationship_image_id", acount_D_map.getInteger("relationship_image_id"));
                    needUpdate = true;
                    device.getUserMap().get(key).put("relationship", acount_D_map.getString("relationship"));
                    device.getUserMap().get(key).put("relationship_image_id", acount_D_map.getInteger("relationship_image_id"));
                    device.getUserMap().get(key).put("phone", acount_D_map.getString("my_phone"));
                }else{
                    tempMap.put("name", item.get("relationship"));
                    tempMap.put("phone", item.get("phone"));
                    tempMap.put("relationship_image_id", item.get("relationship_image_id"));
                }
                if (1 == device.getIsIOTCard()) {
                    //是物联网卡时,家庭成员系列返回是否已添加到白名单的属性标识
                    if (contactMap.keySet().contains(tempMap.get("phone").toString())) {
                        tempMap.put("isAddIOTCard",1);
                        //同时剔除物联网返回的通讯录中的联系人
                        contactMap.remove(tempMap.get("phone").toString());
                    }else{
                        tempMap.put("isAddIOTCard",0);
                    }
                }

                openid_list.add(tempMap);
            }
            //排序
            CollectionUtil.sortDouble(openid_list, "time", 2);

        }

        if(needUpdate){
            //需要更新,更新! 适配旧的数据
            this.updateById(imei, new Update().set("u", device.getUserMap()));
        }
        List<String> needRemoveDuplicateId = new ArrayList<>();

        if (CollectionUtil.isNotEmpty(contactMap)) {
            for (Map.Entry<String, Map<String, Object>> entry : contactMap.entrySet()) {
                //新改版后,需要去重, 把device 中的 通讯录和家庭成员的挑出来
                String identity = (String)entry.getValue().get("identity");
                if(identity != null){
                    if("admin".equals(identity) || "member".equals(identity)){
                        needRemoveDuplicateId.add(entry.getKey());
                        continue;
                    }
                }

                Map<String, Object> tempMap = new HashMap<>();
                tempMap.put("id", entry.getKey());
                tempMap.put("type", 2);
                tempMap.put("name", entry.getValue().get("name"));
                tempMap.put("phone", entry.getValue().get("phone"));
                Object relationship_image_id = entry.getValue().get("relationship_image_id");
                if(relationship_image_id != null){
                    tempMap.put("relationship_image_id", relationship_image_id);
                }else{
                    tempMap.put("relationship_image_id", entry.getValue().get("image"));
                }
                //普通联系人给 默认 "ordinary"
                tempMap.put("identity", "ordinary");
                tempMap.put("time", StringUtil.isNumeric(entry.getValue().get("t")) ? new Double(entry.getValue().get("t").toString()).longValue() : 0);
                if (!StringUtil.isNumeric(entry.getValue().get("image"))) {
                    tempMap.put("avator", baseBucketTool.getDOMAIN() + BaseBucketTool.CONTACT_COMMON_PATH
                            + (StringUtil.isBlank(entry.getValue().get("image")) ? Const.DEFAULT_JPG : entry.getValue().get("image")));
                }
                whiteContacts.add(tempMap);
            }
            //排序
            CollectionUtil.sortDouble(whiteContacts, "time", 2);
        }

        //TODO 为了兼容 Python => Java 的衔接, 暂时不清空 通讯录中的家庭成员信息
//        //新改版后,需要去重, 把device 中的 通讯录和家庭成员的挑出来
//        if(needRemoveDuplicateId.size() > 0){
//            for (String id: needRemoveDuplicateId) {
//                device.getContactMap().remove(id);
//            }
//            UpdateVO updateVO = new UpdateVO();
//            this.updateById(imei, new Update().set("c", device.getContactMap()));
//        }
        JSONArray allList = new JSONArray();
        allList.addAll(openid_list);
        allList.addAll(whiteContacts);
        data.put("whiteContacts", allList);
        return data;
    }
    
    /**
     * @description 查询电话本/通信录
     * @author cwj
     * @param [imei]
     * @return java.util.List<java.util.Map<java.lang.String,java.lang.Object>>
     * @date @time 2024/12/26 18:13
     **/
    public List<Map<String, Object>> obtainContact(String imei){
        Device device = this.findById(imei);
        if (device == null) {
            log.error("Device is null. _id={}", imei);
            return null;
        }
        ResponseMap data = ResponseMap.success();
        data.put("isIOTCard", device.getIsIOTCard());
        Map<String, Map<String, Object>> contactMap = device.getContactMap();
        //TODO 判断设备是否是物联网卡
        if(device.getWatchCustomFunction() != null && 1 == device.getIsIOTCard() && device.getWatchCustomFunction().contains("IOTCard:RJ")){
            IotCardInfo iotCardInfo = iotCardInfoService.findById(device.getIccid());
            //使用物联网卡记录的 通讯录
            contactMap = iotCardInfo.getContactMap();
        }
        List<Map<String, Object>> contacts = new ArrayList<>();
        boolean needUpdate = false;
        if (CollectionUtil.isNotEmpty(device.getUserMap())) {
            for (String key : device.getUserMap().keySet()) {
                Map<String, Object> tempMap = new HashMap<>();
                JSONObject item = new JSONObject(device.getUserMap().get(key));
                tempMap.put("time", StringUtil.isNumeric(item.get("t")) ? item.getDouble("t").longValue() : 0);
                //设置自动接听状态为未开启
                tempMap.put("selected",0);
                //用户联系人给 默认 "member" 成员
                Account tempAccount = accountService.findById(key);
                tempMap.put("avator", baseBucketTool.getDOMAIN() + BaseBucketTool.ACCOUNT_COMMON_PATH
                        + (StringUtil.isBlank(tempAccount.getImage()) ? Const.DEFAULT_JPG : tempAccount.getImage()));
                if(item.get("relationship") == null || item.get("phone") == null || item.get("relationship_image_id") == null ){
                    JSONObject acount_D_map = new JSONObject(tempAccount.getDeviceMap().get(imei));
                    tempMap.put("name", acount_D_map.getString("relationship"));
                    tempMap.put("phone", acount_D_map.getString("my_phone"));
                    tempMap.put("relationship_image_id", acount_D_map.getInteger("relationship_image_id"));
                    needUpdate = true;
                    device.getUserMap().get(key).put("relationship", acount_D_map.getString("relationship"));
                    device.getUserMap().get(key).put("relationship_image_id", acount_D_map.getInteger("relationship_image_id"));
                    device.getUserMap().get(key).put("phone", acount_D_map.getString("my_phone"));
                }else{
                    tempMap.put("name", item.get("relationship"));
                    tempMap.put("phone", item.get("phone"));
                    tempMap.put("relationship_image_id", item.get("relationship_image_id"));
                }
                if (1 == device.getIsIOTCard()) {
                    //是物联网卡时,家庭成员系列返回是否已添加到白名单的属性标识
                    if (contactMap.keySet().contains(tempMap.get("phone").toString())) {
                        //tempMap.put("isAddIOTCard",1);
                        //同时剔除物联网返回的通讯录中的联系人
                        contactMap.remove(tempMap.get("phone").toString());
                    }
                }
                contacts.add(tempMap);
            }
            //排序
            //CollectionUtil.sortDouble(contacts, "time", 2);
        }

        if(needUpdate){
            //需要更新,更新! 适配旧的数据
            this.updateById(imei, new Update().set("u", device.getUserMap()));
        }

        if (CollectionUtil.isNotEmpty(contactMap)) {
            for (Map.Entry<String, Map<String, Object>> entry : contactMap.entrySet()) {
                //新改版后,需要去重, 把device 中的 通讯录和家庭成员的挑出来
                String identity = (String)entry.getValue().get("identity");
                if(identity != null){
                    if("admin".equals(identity) || "member".equals(identity)){
                        continue;
                    }
                }
                Map<String, Object> tempMap = new HashMap<>();
                //设置自动接听状态为未开启
                tempMap.put("selected",0);
                tempMap.put("name", entry.getValue().get("name"));
                tempMap.put("phone", entry.getValue().get("phone"));
                Object relationship_image_id = entry.getValue().get("relationship_image_id");
                if(relationship_image_id != null){
                    tempMap.put("relationship_image_id", relationship_image_id);
                }else{
                    tempMap.put("relationship_image_id", entry.getValue().get("image"));
                }
                tempMap.put("time", StringUtil.isNumeric(entry.getValue().get("t")) ? new Double(entry.getValue().get("t").toString()).longValue() : 0);
                if (!StringUtil.isNumeric(entry.getValue().get("image"))) {
                    tempMap.put("avator", baseBucketTool.getDOMAIN() + BaseBucketTool.CONTACT_COMMON_PATH
                            + (StringUtil.isBlank(entry.getValue().get("image")) ? Const.DEFAULT_JPG : entry.getValue().get("image")));
                }
                contacts.add(tempMap);
            }
            //倒叙排
            CollectionUtil.sortDouble(contacts, "time", 2);
        }
        return contacts;
    }


    /**
     * 添加通讯录
     *
     * @param imei
     * @param vo
     * @param image
     * @time: 2020/12/4 11:43
     * @author: Rock
     * @version 1.0
     */
    public ResponseMap addContact(String imei, DeviceAddContactReqVO vo, MultipartFile image) throws IOException {
        Device device = this.findById(imei);
        if (device == null) {
            log.error("Device is null. _id={}", imei);
            return ResponseMap.fail(ResponseEnum.STATUS2001.getCode(), ResponseEnum.STATUS2001.getMsg(), imei);
        }
        if(device.getUserMap() == null || !device.getUserMap().keySet().contains(vo.getOpenid())){
            //没有绑定关系,不允许操作
            return ResponseMap.fail("请先绑定设备");
        }
        ResponseMap res = ResponseMap.success();
        if ( 1 == device.getIsIOTCard() && device.getWatchCustomFunction().contains("IOTCard:RJ") ){
            //物联网卡白名单也得检查是否和家庭成员重号
            //同时也得检测设备的家庭成员号码是否重复
            for (Map.Entry<String, Map<String, Object>> entry : device.getUserMap().entrySet()) {
                if (vo.getPhone().equals(entry.getValue().get("phone"))) {
                    //号码已存在 API.request.contactAlready
                    return ResponseMap.fail(ResponseEnum.STATUS403.getCode(),"API.request.contactAlready");
                }
            }
            //去物联网卡运营商 添加
            Object addRes = RuiJiIOTUtil.doRJCardWhiteList(device.getIccid(), vo.getPhone(), true);
            if(addRes instanceof Boolean){
                //成功, 昵称 +手机号存储起来
                IotCardInfo iotCardInfo = iotCardInfoService.findById(device.getIccid());
                if(iotCardInfo != null){
                    Map<String, Object> item = new HashMap<>();
                    item.put("phone", vo.getPhone());
                    item.put("name", vo.getName());
                    item.put("t", DateUtil.nowTimestampToLong());
                    iotCardInfo.getContactMap().put(vo.getPhone(),item);
                    iotCardInfoService.save(iotCardInfo);
                    res.put("id", vo.getPhone());
                    //发送kafka
                    JSONObject kafkaJson = new JSONObject();
                    kafkaJson.put("handleFlag", 1);
                    kafkaService.emitDeviceDemand(imei, ConstKafka.DEVICE_TYPE_Contact, kafkaJson, vo.getOpenid());
                    return res;
                }else{
                    return ResponseMap.fail("miss iotCardInfo");
                }

            }else {
                //失败, 信息直接透传前端
                return ResponseMap.fail((String)addRes);
            }
        }
        if (device.getContactMap() != null) {
            for (Map.Entry<String, Map<String, Object>> entry : device.getContactMap().entrySet()) {
                if (vo.getPhone().equals(entry.getValue().get("phone"))) {
                    //号码已存在 API.request.contactAlready
                    return ResponseMap.fail(ResponseEnum.STATUS403.getCode(),"API.request.contactAlready");
                }
            }
            //同时也得检测设备的家庭成员号码是否重复
            for (Map.Entry<String, Map<String, Object>> entry : device.getUserMap().entrySet()) {
                if (vo.getPhone().equals(entry.getValue().get("phone"))) {
                    //号码已存在 API.request.contactAlready
                    return ResponseMap.fail(ResponseEnum.STATUS403.getCode(),"API.request.contactAlready");
                }
            }
            // 通讯录和家庭成员合起来超过 DEVICE_OPENID_NUM 限定次数(50次?)
            int num = 0;
            if(device.getUserMap() != null){
                num = device.getUserMap().size();
            }
            int sumNum = device.getContactMap().size() + num;
            //TODO 为了兼容 Python => Java 的衔接, 判断数量时需要把 通讯录 中的 家庭成员(有openid)的数量滤掉,防止重复
            int haveOpenidNum = 0;
            for (String key : device.getContactMap().keySet()) {
                Map<String, Object> itemMap = device.getContactMap().get(key);
                if (itemMap.containsKey("openid")) {
                    haveOpenidNum += 1;
                }
            }
            sumNum = sumNum - haveOpenidNum;
            if (sumNum >= Constant.DEVICE_OPENID_NUM) {
                return ResponseMap.fail(ResponseEnum.STATUS4010.getCode(), "API.request.contantNumLimit", Constant.DEVICE_OPENID_NUM);
            }
        } else {
            device.setContactMap(new HashMap<>());
        }
        Integer maxSerialNum = null;
        String maxSerialNumRedisValue = redisFilterService.get(imei+Constant.MAX_SERIAL_NUM_KEY_POSTFIX);
        if(StringUtils.isNotEmpty(maxSerialNumRedisValue)){
            maxSerialNum = Integer.valueOf(maxSerialNumRedisValue);
        }
        Update update = new Update();
        List<Map<String, Object>> memberList = new ArrayList<>();
        List<Map<String, Object>> contactMapList = new ArrayList<>();
        Map<String, Map<String, Object>> deviceContactMap = new HashMap<>();
        int index = 0;
        int currentSerialNo = 0;
        //检查一下家庭成员（绑定设备的联系人）和普通联系人都是否有联系人编号，没有则排序后更新各自编号
        //检查编号，是否为空，为空则更新编码，否则走下面的逻辑
        if(isSerialNumNull(device)) {
            //检查家庭成员及联系人的编号是否为空，为空则设置更新家庭成员或联系人的编号
            index = checkSerialNumAndSetUpdate(device, memberList, update, index, contactMapList, deviceContactMap);
            currentSerialNo = index +1;
            maxSerialNum = index + 1;
        } else {
            List<Map<String, Object>> allContactList = new ArrayList<>();
            //合并联系人数据
            assembleAllContactData(device, allContactList);
            //根据编号进行排序
            if(CollectionUtils.isNotEmpty(allContactList)) {
                //按从小到达顺序进行排序
                CollectionUtil.sortByKeyType(allContactList, "serialNum", 2);
                //说明其中存在已经删除掉的编号，可以复用该编号
                if(checkeSerialNumDeficiency(allContactList)) {
                    //遍历数组，取出其中空出的数据进行设置，获取当前设备的编码
                    currentSerialNo = getCurrentSerialNum(allContactList, currentSerialNo);
                    //没找到空缺的编号
                    if(currentSerialNo == 0) {
                        if(ObjectUtils.isEmpty(maxSerialNum)) {
                            maxSerialNum = allContactList.size();
                        }
                        if(maxSerialNum >= Constant.DEVICE_OPENID_NUM) {
                            return ResponseMap.fail(ResponseEnum.STATUS4010.getCode(), "API.request.contantNumLimit", Constant.DEVICE_OPENID_NUM);
                        }
                        currentSerialNo = maxSerialNum + 1;
                        maxSerialNum++;
                    } else {
                        if(ObjectUtils.isEmpty(maxSerialNum) || !maxSerialNum.equals(allContactList.size())) {
                            maxSerialNum = allContactList.size();
                        }
                    }
                } else {
                    //没有遗漏的编号，说明联系人中没有空缺的编号，新加的编号就直接往上加即可
                    maxSerialNum = allContactList.size();
                    //超过限制，则不允许再设置联系人
                    if(maxSerialNum >= Constant.DEVICE_OPENID_NUM) {
                        return ResponseMap.fail(ResponseEnum.STATUS4010.getCode(), "API.request.contantNumLimit", Constant.DEVICE_OPENID_NUM);
                    }
                    maxSerialNum++;
                    currentSerialNo = maxSerialNum;
                }
            } else {
                currentSerialNo = 1;
                maxSerialNum = 1;
            }
            deviceContactMap = device.getContactMap();
        }
        Map<String, Object> contactMap = new HashMap<>();
        contactMap.put("t", DateUtil.nowTimestampToLong());
        contactMap.put("c", vo.getOpenid());
        //添加联系人编码序号
        contactMap.put("serialNum",currentSerialNo);
        contactMap.put("name", vo.getName());
        contactMap.put("phone", vo.getPhone());
        if(vo.getRelationship_image_id() != null){
            contactMap.put("relationship_image_id", vo.getRelationship_image_id());
        }
        if (image != null && !image.isEmpty()) {
                //生成文件名并上传
            String fileName = BaseBucketTool.createFileNameToJpg();
            baseBucketTool.upload(BaseBucketTool.CONTACT_COMMON_PATH + fileName, image, 1);
            contactMap.put("image", fileName);
            res.put("avator", baseBucketTool.getDOMAIN() + BaseBucketTool.DEVICE_COMMON_PATH + fileName);
        }
        String cid = RandomUtil.getRandomStr(8);
            //更新联系人
        deviceContactMap.put(cid,contactMap);
        update.set("c",deviceContactMap);
        //device.getContactMap().put(cid, contactMap);
        //this.updateById(device.getId(), new Update().set("c", device.getContactMap()));
        //更新联系人或家庭成员（或二者一起更新）
        this.updateById(device.getId(),update);
        res.put("id", cid);
        //发送kafka
        JSONObject kafkaJson = new JSONObject();
        //kafkaJson.put("handleFlag", 1);
        kafkaJson.put("serialNum",contactMap.get("serialNum").toString());
        kafkaJson.put("name",vo.getName());
        kafkaJson.put("phone",vo.getPhone());
        if (ObjectUtils.isNotEmpty(contactMap.get("image")) && !StringTool.isInteger(contactMap.get("image").toString())) {
            String fileName = contactMap.get("image").toString();
            kafkaJson.put("avator",baseBucketTool.getDOMAIN() + BaseBucketTool.DEVICE_COMMON_PATH + fileName);
        }
        log.info("发送数据的编号为：{}",kafkaJson.getString("serialNum"));
        //kafkaService.emitDeviceDemand(imei, ConstKafka.DEVICE_TYPE_Contact, kafkaJson, vo.getOpenid());
        kafkaService.emitDeviceDemand(imei, ConstKafka.DEVICE_TYPE_ADD_CONTACT, kafkaJson, vo.getOpenid());
        //缓存当前最大序列号
        redisFilterService.set(imei+Constant.MAX_SERIAL_NUM_KEY_POSTFIX,maxSerialNum.toString());
        /* } else {
            //新微聊协议添加新协议的联系人
            addNewContact(imei, vo, image, device, res);
        }*/
        return res;
    }

    /**
     * @description 添加新版联系人
     * @author cwj
     * @param [imei, vo, image, device, res]
     * @return void
     * @date @time 2025/6/22 11:15
     **/
    private void addNewContact(String imei, DeviceAddContactReqVO vo, MultipartFile image, Device device, ResponseMap res) throws IOException {
        //设备为新版微聊协议的联系人
        Update update = new Update();
        Map<String, Map<String, Object>> deviceContactMap = device.getContactMap();
        Map<String, Object> contactMap = new HashMap<>();
        contactMap.put("t", DateUtil.nowTimestampToLong());
        contactMap.put("c", vo.getOpenid());
        //添加联系人编码序号
        contactMap.put("name", vo.getName());
        contactMap.put("phone", vo.getPhone());
        if(vo.getRelationship_image_id() != null){
            contactMap.put("relationship_image_id", vo.getRelationship_image_id());
        }
        if (image != null && !image.isEmpty()) {
            //生成文件名并上传
            String fileName = BaseBucketTool.createFileNameToJpg();
            baseBucketTool.upload(BaseBucketTool.CONTACT_COMMON_PATH + fileName, image, 1);
            contactMap.put("image", fileName);
            res.put("avator", baseBucketTool.getDOMAIN() + BaseBucketTool.DEVICE_COMMON_PATH + fileName);
        }
        String cid = RandomUtil.getRandomStr(8);
        //更新联系人
        deviceContactMap.put(cid,contactMap);
        update.set("c",deviceContactMap);
        //更新联系人
        this.updateById(device.getId(),update);
        res.put("id", cid);
        JSONObject kafkaJson = new JSONObject();
        kafkaJson.put("name", vo.getName());
        kafkaJson.put("phone", vo.getPhone());
        if (ObjectUtils.isNotEmpty(contactMap.get("image")) && !StringTool.isInteger(contactMap.get("image").toString())) {
            String fileName = contactMap.get("image").toString();
            kafkaJson.put("avator",baseBucketTool.getDOMAIN() + BaseBucketTool.DEVICE_COMMON_PATH + fileName);
        }
        kafkaService.emitDeviceDemand(imei, ConstKafka.DEVICE_TYPE_ADD_NEW_CONTACT, kafkaJson, vo.getOpenid());
    }


    /**
     * @description 检查家庭成员和联系人是否存在编号为空的数据
     * @author cwj
     * @param [device]
     * @return boolean
     * @date @time 2025/6/9 16:45
     **/
    private boolean isSerialNumNull(Device device){
        boolean isUserNotExistsNumber = false;
        boolean isContactNotExistsNumber = false;
        if(ObjectUtils.isNotEmpty(device.getUserMap())) {
            for (Map.Entry<String, Map<String, Object>> entry : device.getUserMap().entrySet()) {
                Map<String, Object> userMapValue = entry.getValue();
                if(ObjectUtils.isEmpty(userMapValue.get("serialNum"))) {
                    isUserNotExistsNumber = true;
                    break;
                }
            }
        }
        if(ObjectUtils.isNotEmpty(device.getContactMap())) {
            for (Map.Entry<String, Map<String, Object>> entry : device.getContactMap().entrySet()) {
                Map<String, Object> contactMapValue = entry.getValue();
                if (ObjectUtils.isEmpty(contactMapValue.get("serialNum"))) {
                    isContactNotExistsNumber = true;
                    break;
                }
            }
        }
        return isUserNotExistsNumber || isContactNotExistsNumber;
    }

    /**
     * @description 检查家庭成员及联系人的编号是否为空，为空则设置更新家庭成员或联系人的编号
     * @author cwj
     * @param [device, memberList, update, index, contactMapList, deviceContactMap]
     * @return int
     * @date @time 2025/6/9 16:39
     **/
    private int checkSerialNumAndSetUpdate(Device device, List<Map<String, Object>> memberList, Update update, int index, List<Map<String, Object>> contactMapList, Map<String, Map<String, Object>> deviceContactMap) {
        //检查家庭成员的编码是否为空，为空则按顺序赋值
        checkUserMapSerialNumber(device, memberList, update);
        if(CollectionUtils.isNotEmpty(memberList)){
            index = memberList.size();
        }
        //检查一下普通联系人有没有联系人编码，如果没有则补上编码
        index = checkContactMapSerialNumber(device, contactMapList, index, deviceContactMap);
        return index;
    }

    /**
     * @description 将某个设备的所有联系人数据合并到一个list中
     * @author cwj
     * @param [device, allContactList]
     * @return void
     * @date @time 2025/5/21 17:45
     **/
    private void assembleAllContactData(Device device, List<Map<String, Object>> allContactList) {
        if(ObjectUtils.isNotEmpty(device.getUserMap())) {
            for (Map.Entry<String, Map<String, Object>> entry : device.getUserMap().entrySet()) {
                Map<String, Object> userMapValue = entry.getValue();
                Map<String, Object> umv = new HashMap<>();
                umv.put("id",entry.getKey());
                umv.put("serialNum",userMapValue.get("serialNum"));
                allContactList.add(umv);
            }
        }
        if(ObjectUtils.isNotEmpty(device.getContactMap())) {
            if(ObjectUtils.isNotEmpty(device.getUserMap())) {
                 //过滤掉重复存在于家庭成员和联系人中的记录
                for (Map.Entry<String, Map<String, Object>> entry : device.getContactMap().entrySet()) {
                    Map<String, Object> contactMapValue = entry.getValue();
                    boolean isContactExists = false;
                    for (Map.Entry<String, Map<String, Object>> userMap : device.getUserMap().entrySet()){
                        Map<String, Object> userMapValue = userMap.getValue();
                        if(userMapValue.get("phone").toString().equals(contactMapValue.get("phone").toString())){
                            isContactExists = true;
                            break;
                        }
                    }
                    if(!isContactExists) {
                        Map<String, Object> cmv = new HashMap<>();
                        cmv.put("id", entry.getKey());
                        cmv.put("serialNum", contactMapValue.get("serialNum"));
                        allContactList.add(cmv);
                    }
                }
            } else {
                for (Map.Entry<String, Map<String, Object>> entry : device.getContactMap().entrySet()) {
                    Map<String, Object> contactMapValue = entry.getValue();
                    Map<String, Object> cmv = new HashMap<>();
                    cmv.put("id", entry.getKey());
                    cmv.put("serialNum", contactMapValue.get("serialNum"));
                    allContactList.add(cmv);
                }
            }
        }
    }

    /**
     * @description 检查联系人编码序号是否存在
     * @author cwj
     * @param [device, contactMapList, index, deviceContactMap]
     * @return int
     * @date @time 2025/5/21 15:49
     **/
    private int checkContactMapSerialNumber(Device device, List<Map<String, Object>> contactMapList, int index, Map<String, Map<String, Object>> deviceContactMap) {
        boolean isContactNotExistsNumber = false;
        if(ObjectUtils.isNotEmpty(device.getContactMap())) {
            for (Map.Entry<String, Map<String, Object>> entry : device.getContactMap().entrySet()) {
                Map<String, Object> contactMapValue = entry.getValue();
                contactMapValue.put("id",entry.getKey());
                if(ObjectUtils.isEmpty(contactMapValue.get("serialNum"))) {
                    isContactNotExistsNumber = true;
                }
                contactMapList.add(contactMapValue);
            }
        }
        if(isContactNotExistsNumber && CollectionUtils.isNotEmpty(contactMapList)) {
            CollectionUtil.sortDouble(contactMapList, "t", 2);
            if(ObjectUtils.isEmpty(device.getUserMap())) {
                for(int i = 0; i< contactMapList.size(); i++){
                    index += i+1;
                    Map<String, Object> contactMapValue = contactMapList.get(i);
                    String key = (String) contactMapValue.get("id");
                    //加上编号
                    contactMapValue.put("serialNum", index);
                    contactMapValue.remove("id");
                    deviceContactMap.put(key,contactMapValue);
                }
            } else {
                for(int i = 0; i< contactMapList.size(); i++){
                    Map<String, Object> contactMapValue = contactMapList.get(i);
                    String key = (String) contactMapValue.get("id");
                    boolean isContactExists = false;
                    Integer existsSerialNum = null;
                    for (Map.Entry<String, Map<String, Object>> entry : device.getUserMap().entrySet()) {
                        Map<String, Object> userMapValue = entry.getValue();
                        if(userMapValue.get("phone").toString().equals(contactMapValue.get("phone").toString())) {
                            isContactExists = true;
                            if(ObjectUtils.isNotEmpty(userMapValue.get("serialNum"))) {
                                existsSerialNum = Integer.valueOf(userMapValue.get("serialNum").toString());
                            }
                            break;
                        }
                    }
                    if(isContactExists && ObjectUtils.isNotEmpty(existsSerialNum)) {
                        contactMapValue.put("serialNum", existsSerialNum);
                    } else {
                        index++;
                        contactMapValue.put("serialNum", index);
                    }
                    contactMapValue.remove("id");
                    deviceContactMap.put(key,contactMapValue);
                }
            }
        }
        return index;
    }


    /**
     * @description 检验家庭成员是否存在编码序号
     * @author cwj
     * @param [device, memberList, update]
     * @return void
     * @date @time 2025/5/21 15:48
     **/
    private void checkUserMapSerialNumber(Device device, List<Map<String, Object>> memberList, Update update) {
        //是否有没有编号的数据存在
        boolean isUserNotExistsNumber = false;
        Map<String, Map<String, Object>> userMap = new HashMap<>();
        if(ObjectUtils.isNotEmpty(device.getUserMap())) {
            for (Map.Entry<String, Map<String, Object>> entry : device.getUserMap().entrySet()) {
                Map<String, Object> userMapValue = entry.getValue();
                userMapValue.put("id",entry.getKey());
                if(ObjectUtils.isEmpty(userMapValue.get("serialNum"))) {
                    isUserNotExistsNumber = true;
                }
                memberList.add(userMapValue);
            }
        }
        if(isUserNotExistsNumber && CollectionUtils.isNotEmpty(memberList)) {
            CollectionUtil.sortDouble(memberList, "t", 2);
            for(int i = 0; i< memberList.size(); i++){
                Map<String, Object> userMapValue = memberList.get(i);
                String key = (String) userMapValue.get("id");
                //加上编号
                userMapValue.put("serialNum",i+1);
                userMapValue.remove("id");
                userMap.put(key,userMapValue);
            }
            update.set("u", userMap);
            device.setUserMap(userMap);
        }
    }

    /**
     * 修改设备通讯录记录
     * APP将用户信息也在此进行修改, 使用 type 进行区分
     *
     * @param imei
     * @param vo
     * @param image
     * @time: 2021/1/12 17:59
     * @author: Rock
     * @version 1.0
     */
    public ResponseMap updateContact(String imei, DeviceUpdateContactReqVO vo, MultipartFile image) throws IOException {
        ResponseMap res = ResponseMap.success();
        Device device = this.findById(imei);
        if (device == null) {
            log.error("Device is null. _id={}", imei);
            return ResponseMap.fail(ResponseEnum.STATUS2001.getCode(), ResponseEnum.STATUS2001.getMsg(), imei);
        }
        //设备的家庭成员
        Map<String, Map<String, Object>> devUserMap = device.getUserMap();
        Account account = accountService.findById(vo.getOpenid());
        //管理员转让
        if(vo.getTransfer() != null && vo.getTransfer() == 1){
            //管理员转让, 仅限于管理员操作
            if(!accountService.checkAccountIsAdminWithImei(account, imei)){
                //仅限于管理员操作  API.request.onlyAdminOperation
                return ResponseMap.fail(ResponseEnum.STATUS403.getCode(), "API.request.onlyAdminOperation");
            }
            //设置管理员和成员的account表的 d（2个）
            account.getDeviceMap().get(imei).put("identity","member"); //设置成成员
            //被转让的成员Account
            Account transferAccount = accountService.findById(vo.getId());
            transferAccount.getDeviceMap().get(imei).put("identity","admin");//设置成管理员
            //更新
            accountService.updateById(account.getId(), new Update().set("d", account.getDeviceMap()));
            accountService.updateById(transferAccount.getId(), new Update().set("d", transferAccount.getDeviceMap()));
            Update devUpdate = new Update();
            //设置管理员和成员的device表中的设备绑定的用户u字段（2个）
            Map<String, Map<String, Object>> userMap = device.getUserMap();
            for (Map.Entry<String, Map<String, Object>> entry : userMap.entrySet()) {
                if(entry.getKey().equals(transferAccount.getId())){
                    entry.getValue().put("identity", "admin");
                }
                if(entry.getKey().equals(account.getId())){
                    entry.getValue().put("identity", "member");
                }
            }
            devUpdate.set("u", userMap);
            //同时也要检测一下, 更新 checked_openids 中的信息
            Map<String, Map<String, Object>> checkedOpenidsMap = device.getCheckedOpenidsMap();
            if (checkedOpenidsMap != null && checkedOpenidsMap.size() > 0) {
                if(checkedOpenidsMap.containsKey(transferAccount.getId())){
                    checkedOpenidsMap.get(transferAccount.getId()).put("identity", "admin");
                }
                if(checkedOpenidsMap.containsKey(account.getId())){
                    checkedOpenidsMap.get(account.getId()).put("identity", "member");
                }
            }
            devUpdate.set("checked_openids", checkedOpenidsMap);
            //更新
            this.updateById(imei, devUpdate);

            // 创建 转让消息的消息记录 (2条)
            String deviceName = this.getDeviceName(device);
            // 管理员主动转移身份给成员， 你把管理员身份转给用户（成员）
            DeviceNotification tempDeviceNotification = new DeviceNotification();
            tempDeviceNotification.setImei(imei);
            tempDeviceNotification.setName(deviceName);
            tempDeviceNotification.setType("identityTransfer");
            //被转者的号码
            tempDeviceNotification.setPhone(transferAccount.getPhone());
            tempDeviceNotification.setTransfered_openid(transferAccount.getId());
            tempDeviceNotification.setOpenid(account.getId());
            deviceNotificationService.createNewNotification(tempDeviceNotification);
            // 成员被接受成为管理员，用户（管理员）把管理员身份转移给你
            tempDeviceNotification.setId(null);
            tempDeviceNotification.setTransfered_openid(null);
            tempDeviceNotification.setOpenid(transferAccount.getId());
            tempDeviceNotification.setType("identityTransfered");
            //管理员的号码
            tempDeviceNotification.setPhone(account.getPhone());
            deviceNotificationService.createNewNotification(tempDeviceNotification);
            // 发送推送(2条)
            //您已把手表(%s)的管理员身份转移给(%s)  //(转移者) //API.request.adminTransferTitle
            String megTitle = MessageUtils.getLocale("API.request.adminTransferTitle", deviceName, transferAccount.getPhone());
            JSONObject pushMsgOb = new JSONObject();
            pushMsgOb.put("type", ConstPush.ACCOUNT_MESSAGE);
            JSONObject messageOb = new JSONObject();
            messageOb.put("imei", imei);
            messageOb.put("type", "identityTransfer");
            messageOb.put("name", deviceName);
            messageOb.put("timestamp", DateUtil.nowTimestampToLong());
            //被转者的电话
            messageOb.put("phone", transferAccount.getPhone());
            messageOb.put("msgTitle", megTitle);

            pushMsgOb.put("message", messageOb);
            kafkaService.sendPushToAccount(ConstKafka.ACCOUNT_TYPE_3, account.getId(),pushMsgOb);

            //[%s]手表的管理员(%s)把 管理员身份转移给您 //(被转者) //API.request.adminTransferedTitle
            megTitle = MessageUtils.getLocale("API.request.adminTransferedTitle", deviceName, account.getPhone());
            messageOb.put("type", "identityTransfered");
            //管理员的电话
            messageOb.put("phone", account.getPhone());
            messageOb.put("msgTitle", megTitle);
            pushMsgOb.put("message", messageOb);
            kafkaService.sendPushToAccount(ConstKafka.ACCOUNT_TYPE_3, transferAccount.getId(),pushMsgOb);

            log.info("imei:{} openid:{} 转移管理员身份成功 transferOpenid:{}",imei, account.getId(), transferAccount.getId());

            // 清空原管理员的所有绑定手表申请记录 并发失效推送给申请者
            Query query = new Query();
            query.addCriteria(Criteria.where("openid").is(account.getId()).and("T").is("applicationRrecord").and("i").is(imei));
            List<DeviceAttention> messagesList = deviceAttentionService.messageQueryHandle(query.getQueryObject(), Filters.eq("t", -1), 0, -1);
            for (DeviceAttention item : messagesList) {
                String apply_openid = item.getApply_openid(); //申请人openid
                String apply_id = item.getId(); //消息id
                String apply_phone = item.getPhone(); //申请人手机号
                deviceAttentionService.delById(new ObjectId(apply_id));
                DeviceAttention tempNewAtt = new DeviceAttention();
                tempNewAtt.setImei(imei);
                tempNewAtt.setName(deviceName);
                tempNewAtt.setType("applicationOvertime");
                tempNewAtt.setPhone(apply_phone);
                tempNewAtt.setTimestamp(DateUtil.nowTimestampToLong());
                tempNewAtt.setOpenid(account.getId());
                deviceAttentionService.createNewAttention(tempNewAtt);
                tempNewAtt.setId(null);
                tempNewAtt.setOpenid(apply_openid);
                deviceAttentionService.createNewAttention(tempNewAtt);

                JSONObject pushOverTimeOb = new JSONObject();
                pushOverTimeOb.put("type", ConstPush.ACCOUNT_MESSAGE);
                JSONObject overTimeMessageOb = new JSONObject();
                overTimeMessageOb.put("imei", imei);
                overTimeMessageOb.put("type", "identityTransfer");
                overTimeMessageOb.put("name", deviceName);
                overTimeMessageOb.put("phone", apply_phone);
                overTimeMessageOb.put("timestamp", DateUtil.nowTimestampToLong());
                pushOverTimeOb.put("message", overTimeMessageOb);
                kafkaService.sendPushToAccount(ConstKafka.ACCOUNT_TYPE_3, apply_openid,pushOverTimeOb);
            }
            // 获取一下redis 中是否有这个设备标识头, 如果有的话证明是三基协议的 (需要下发一下中心号码)centerPhone
            String devHeartIdent = redisClusterService.hget(imei, "deviceHead");
            if(devHeartIdent != null){
                JSONObject centerPhoneData = new JSONObject();
                centerPhoneData.put("phone", transferAccount.getPhone());
                kafkaService.emitDeviceDemand(device.getId(), ConstKafka.DEVICE_TYPE_CenterPhone, centerPhoneData, vo.getOpenid());
                log.info("imei:{} openid:{} 转移管理员身份 transferOpenid:{} 中心号码下发:{}",
                        imei, account.getId(), transferAccount.getId(), transferAccount.getPhone());
            }
            return res;
        }

        if (Const.INT_1.equals(vo.getType())) {
            //只能修改自身的用户信息+
            if (account == null) {
                log.error("Account is null. _id={}", vo.getOpenid());
                return ResponseMap.fail(ResponseEnum.STATUS2000.getCode(), ResponseEnum.STATUS2000.getMsg());
            }
            if (device.getContactMap() != null  && StringUtils.isNotEmpty(vo.getPhone())) {
                //不能修改成与其他号码重复的
                for (Map.Entry<String, Map<String, Object>> entry : device.getContactMap().entrySet()) {
                    String identity = (String)entry.getValue().get("identity");
                    //不能修改成员的电话号码，设备绑定的电话号码是不能修改的
                    if(("admin".equals(identity) || "member".equals(identity)) && vo.getId().equals(entry.getValue().get("c").toString())) {
                        if(!vo.getPhone().equals(entry.getValue().get("phone"))){
                            //自己不能修改自己绑定设备的电话号码
                            return ResponseMap.fail(ResponseEnum.STATUS405.getCode(),"API.request.deviceBindUser.phone.notModify" );
                        }
                    }
                }
            }
            Update updateAccount = new Update();
            //同时更新 account中的 d 中的绑定信息，更新用户绑定的设备信息
            Map<String, Map<String, Object>> userDeviceMaps = account.getDeviceMap();
            Map<String, Object> usr_thisDev = userDeviceMaps.get(imei);
            Update updateDevice = new Update();
            //自身在device中绑定关系的信息（家庭成员中自身）
            Map<String, Object> selfDevUserMap = devUserMap.get(vo.getOpenid());
            Map<String, Object> selfDevCheckedOpenidMap = null;
            if(device.getCheckedOpenidsMap() != null && device.getCheckedOpenidsMap().size() > 0){
                if (device.getCheckedOpenidsMap().containsKey(vo.getOpenid())) {
                    selfDevCheckedOpenidMap = device.getCheckedOpenidsMap().get(vo.getOpenid());
                }
            }
            //修改自身不让改电话号码.
//            if (StringUtil.isNotBlank(vo.getPhone())) {
//                //如果家庭成员中已有人用相同的电话号码,也提示重复
//                for (Map.Entry<String, Map<String, Object>> entry : devUserMap.entrySet()) {
//                    if (vo.getPhone().equals(entry.getValue().get("phone")) &&
//                            !entry.getKey().equals(vo.getOpenid())) {
//                        //号码存在且不是修改自己
//                        //号码已存在 API.request.contactAlready
//                        return ResponseMap.fail(ResponseEnum.STATUS403.getCode(),"API.request.contactAlready");
//                    }
//                }
//                //更新account表的同时也得更新 device表中绑定的 u的信息
//                updateAccount.set("phone", vo.getPhone());
//                selfDevUserMap.put("phone", vo.getPhone());
//                if (selfDevCheckedOpenidMap != null){
//                    selfDevCheckedOpenidMap.put("phone", vo.getPhone());
//                }
//            }
            boolean relationshipChange = false;
            try {
                if (StringUtil.isNotBlank(vo.getName())) {
//                  updateAccount.set("name", vo.getName());
                    if(!vo.getName().equals(selfDevUserMap.get("relationship"))){
                        relationshipChange = true;
                    }
                    selfDevUserMap.put("relationship", vo.getName());
                    usr_thisDev.put("relationship", vo.getName());
                    if (selfDevCheckedOpenidMap != null){
                        selfDevCheckedOpenidMap.put("relationship", vo.getName());
                    }
                }
                boolean relationship_image_idChange = false;
                if (StringUtil.isNotBlank(vo.getRelationship_image_id())) {
                    if(!vo.getRelationship_image_id().equals(selfDevUserMap.get("relationship_image_id"))){
                        relationship_image_idChange = true;
                    }
                    selfDevUserMap.put("relationship_image_id", vo.getRelationship_image_id());
                    usr_thisDev.put("relationship_image_id", vo.getRelationship_image_id());
                    if (selfDevCheckedOpenidMap != null){
                        selfDevCheckedOpenidMap.put("relationship_image_id", vo.getRelationship_image_id());
                    }
                }
                if (image != null && !image.isEmpty()) {
                    //生成文件名并上传
                    String fileName = BaseBucketTool.createFileNameToJpg();
                    baseBucketTool.upload(BaseBucketTool.ACCOUNT_COMMON_PATH + fileName, image, 1);
                    updateAccount.set("image", fileName);
                    selfDevUserMap.put("image",fileName);
                    res.put("avator", baseBucketTool.getDOMAIN() + BaseBucketTool.ACCOUNT_COMMON_PATH + fileName);
                }
                if(relationshipChange || relationship_image_idChange){
                    if (selfDevCheckedOpenidMap != null) { //是视频中的人
                        //如果具有短标识 三基的设备, 需要更新视频联系人
                        if (device.getModules().contains(ConstVideo.V0JF)) {
                            // 有菊风视频
                            String shortId = RedisClusterService.getJedisCluster().hget(device.getId(), "shortId");
                            JSONObject kafkaJson = new JSONObject();
                            if (StringUtils.isNotBlank(shortId)) {
                                if(!ObjectUtils.isEmpty(device.getIsNewWechatProtocol()) && device.getIsNewWechatProtocol().equals(1)) {
                                    if(relationshipChange) {
                                        kafkaJson.put("name",selfDevUserMap.get("relationship"));
                                        //kafkaJson.put("phone",selfDevUserMap.get("phone"));
                                        kafkaJson.put("openId",vo.getOpenid());
                                        //修改新版视频微聊联系人的名字
                                        kafkaService.emitDeviceDemand(imei, ConstKafka.DEVICE_TYPE_UPDATE_NEW_CONTACT_NAME, kafkaJson, account.getId());
                                        wechatContactService.updateWechatContactName(imei,account.getId(),selfDevUserMap.get("relationship").toString());
                                    }
                                } else {
                                    //三基的短标识设备
                                    kafkaJson.put("openid", vo.getOpenid());
                                    kafkaJson.put("phone", selfDevUserMap.get("phone"));
                                    kafkaJson.put("name", selfDevUserMap.get("relationship"));
                                    kafkaJson.put("relationship", selfDevUserMap.get("relationship"));
                                    kafkaJson.put("relationship_image_id", selfDevUserMap.get("relationship_image_id"));
                                    kafkaService.emitDeviceDemand(device.getId(), ConstKafka.DEVICE_TYPE_DownAddVideoContact, kafkaJson, null);
                                }
                            }
                        }
                    }
                }
            } catch (Exception e){
                log.error("imei:"+imei+" 更新自己联系人信息 时错误 error:"+e.getMessage(), e);
            }
            //检查设备
            devUserMap.put(vo.getOpenid(), selfDevUserMap);
            //更新设备的家庭成员（设备的绑定人）
            updateDevice.set("u", devUserMap);
            if (selfDevCheckedOpenidMap != null ) {
                updateDevice.set("checked_openids", device.getCheckedOpenidsMap());
                //同时更新 设备的通讯录 "c" 字段 getContactMap
                for (Map.Entry<String, Map<String, Object>> entry : device.getContactMap().entrySet()) {
                    String identity = (String) entry.getValue().get("identity");
                    //不能修改成员的电话号码，设备绑定的电话号码是不能修改的
                    if(("admin".equals(identity) || "member".equals(identity))
                            && vo.getPhone().equals(entry.getValue().get("phone"))
                            && !vo.getId().equals(entry.getValue().get("c").toString())) {
                    //if (vo.getPhone().equals(entry.getValue().get("phone")) && !entry.getKey().equals(vo.getId())) {
                        //且修改的不是本人ID，说明修改的成员的电话已经有其他成员存在了
                        //号码已存在 API.request.contactAlready
                        return ResponseMap.fail(ResponseEnum.STATUS403.getCode(),"API.request.contactAlready");
                    }else if(("admin".equals(identity) || "member".equals(identity)) && vo.getId().equals(entry.getValue().get("c").toString())){
                        if(!vo.getName().equals(entry.getValue().get("relationship"))){
                            entry.getValue().put("relationship",vo.getName());
                        }
                    }
                }
                updateDevice.set("c", device.getContactMap());
            }
            //检查家庭成员和联系人是否存在，不存在则，按照之前业务发送指令的顺序生成序列号
            if (isSerialNumNull(device)) {
                //更新设备绑定人（家庭成员的编号）
                int index = updateDeviceUserSerialNo(device, devUserMap, updateDevice);
                //更新设备联系人的编号
                updeteDeviceContactSerialNo(device, device.getContactMap(), index, updateDevice);
            }
            //更新用户关联设备信息，更新设备联系人信息，删除旧图像信息
            updateAccountAndDevice(imei, image, updateDevice, account, userDeviceMaps, usr_thisDev, updateAccount);
            //更新家庭成员的关系后也要更新一下通讯录
            //发送kafka
            JSONObject kafkaJson = new JSONObject();
            selfDevUserMap = device.getUserMap().get(vo.getOpenid());
            kafkaJson.put("serialNum", selfDevUserMap.get("serialNum").toString());
            kafkaJson.put("name", selfDevUserMap.get("relationship").toString());
            kafkaJson.put("phone", selfDevUserMap.get("phone").toString());
            if (ObjectUtils.isNotEmpty(selfDevUserMap.get("image")) && !StringTool.isInteger(selfDevUserMap.get("image").toString())) {
                String fileName = "" + selfDevUserMap.get("image");
                kafkaJson.put("avator", baseBucketTool.getDOMAIN() + BaseBucketTool.DEVICE_COMMON_PATH + fileName);
            }
            kafkaService.emitDeviceDemand(imei, ConstKafka.DEVICE_TYPE_ADD_CONTACT, kafkaJson, vo.getOpenid());
            //kafkaJson.put("handleFlag", 3);
            //kafkaService.emitDeviceDemand(imei, ConstKafka.DEVICE_TYPE_Contact, kafkaJson, vo.getOpenid());
            //kafkaService.emitDeviceDemand(imei, ConstKafka.DEVICE_TYPE_Contact, kafkaJson, vo.getOpenid());
            return res;
            /*} else {
                //更新用户关联设备信息，更新设备联系人信息
                updateAccountAndDevice(imei, image, updateDevice, account, userDeviceMaps, usr_thisDev, updateAccount);
                //新版微聊协议更新联系人指令
                sendUpdateContactCommand(imei, vo.getOpenid(), image, relationshipChange,
                        selfDevUserMap.get("relationship"),selfDevUserMap.get("phone"),selfDevUserMap.get("image"));
            }*/
        }

//        if (Const.INT_1.equals(device.getIsIOTCard())) {
//            //物联网卡,得修改昵称
//            IotCardInfo iotCardInfo = iotCardInfoService.findById(device.getIccid());
//            if (iotCardInfo != null) {
//                if (!CollectionUtil.containsKey(iotCardInfo.getContactMap(), vo.getId())) {
//                    return ResponseMap.fail(ResponseEnum.STATUS4006.getCode(), "联系人未找到 " + vo.getId());
//                }
//                if (!vo.getPhone().equals(iotCardInfo.getContactMap().get(vo.getId()).get("phone"))) {
//                    return ResponseMap.fail(ResponseEnum.STATUS500.getCode(), "物联网白名单不支持修改号码,如需修改请联系客服人员处理");
//                }
//                boolean update = CXUtil.updateCXCardWhiteListNickName(device.getIccid(), vo.getName(), vo.getPhone());
//                if (update) {
//                    iotCardInfo.getContactMap().get(vo.getId()).put("name", vo.getName());
//                    iotCardInfoService.updateById(iotCardInfo.getId(), new Update().set("c", iotCardInfo.getContactMap()));
//                    res.put("id", iotCardInfo.getId());
//                    //发送kafka
//                    JSONObject kafkaJson = new JSONObject();
//                    kafkaJson.put("handleFlag", 3);
////                    kafkaJson.put("id", vo.getId());
////                    kafkaJson.put("phone", vo.getPhone());
////                    kafkaJson.put("name", vo.getName());
////                    kafkaJson.put("type", vo.getType());
//                    kafkaService.emitDeviceDemand(imei, ConstKafka.DEVICE_TYPE_Contact, kafkaJson, vo.getOpenid());
//                }
//            }
//            return res;
//        }

        if ( 1 == device.getIsIOTCard() && device.getWatchCustomFunction().contains("IOTCard:RJ") ){
            // 只允许修改昵称
            IotCardInfo iotCardInfo = iotCardInfoService.findById(device.getIccid());
            if(iotCardInfo == null) {
                return ResponseMap.fail("miss iotCardInfo");
            }
            Map<String, Map<String, Object>> contactMap = iotCardInfo.getContactMap();
            Map<String, Object> changeItem = contactMap.get(vo.getId());
            changeItem.put("name", vo.getName());
            contactMap.put(vo.getId(), changeItem);
            iotCardInfo.setContactMap(contactMap);
            iotCardInfoService.save(iotCardInfo);
            //发送kafka
            JSONObject kafkaJson = new JSONObject();
            kafkaJson.put("handleFlag", 3);
//                kafkaJson.put("id", vo.getId());
//                kafkaJson.put("phone", vo.getPhone());
//                kafkaJson.put("name", vo.getName());
//                kafkaJson.put("typeParam", vo.getType());
            kafkaService.emitDeviceDemand(imei, ConstKafka.DEVICE_TYPE_Contact, kafkaJson, vo.getOpenid());
            return res;
//            //不允许修改
//            return ResponseMap.fail("No modification allowed");
        }

        if (new Integer(2).equals(vo.getType())) {
            //修改腕表联系人，只有管理员身份才可以修改
            if(!accountService.checkAccountIsAdminWithImei(account, imei)){
                //仅限于管理员操作  API.request.onlyAdminOperation
                return ResponseMap.fail(ResponseEnum.STATUS403.getCode(), "API.request.onlyAdminOperation");
            }
            if (device.getContactMap() != null && device.getContactMap().containsKey(vo.getId())) {
                Map<String, Map<String, Object>> deviceContactMap = device.getContactMap();
                Map<String, Object> updateContact = deviceContactMap.get(vo.getId());
                boolean phoneChange = false;
                boolean nameChange = false;
                String oldPhone = updateContact.get("phone").toString();
                if (StringUtil.isNotBlank(vo.getPhone())) {
                    if(!vo.getPhone().equals(updateContact.get("phone"))) {
                        phoneChange = true;
                    }
                    //不能修改成与其他号码重复的
                    for (Map.Entry<String, Map<String, Object>> entry : device.getContactMap().entrySet()) {
                        if (vo.getPhone().equals(entry.getValue().get("phone")) && !entry.getKey().equals(vo.getId())) {
                            //且修改的不是本人ID，号码已存在 API.request.contactAlready
                            return ResponseMap.fail(ResponseEnum.STATUS403.getCode(),"API.request.contactAlready");
                        }
                    }
                    //如果家庭成员中已有人用相同的电话号码,也提示重复
                    for (Map.Entry<String, Map<String, Object>> entry : devUserMap.entrySet()) {
                        if (vo.getPhone().equals(entry.getValue().get("phone"))) {
                            //号码已存在 API.request.contactAlready
                            return ResponseMap.fail(ResponseEnum.STATUS403.getCode(),"API.request.contactAlready");
                        }
                    }
                    updateContact.put("phone", vo.getPhone());
                }
                if (StringUtil.isNotBlank(vo.getName())) {
                    if (!vo.getName().equals(updateContact.get("name"))) {
                        nameChange = true;
                    }
                    updateContact.put("name", vo.getName());
                }
                if (StringUtil.isNotBlank(vo.getRelationship_image_id())) {
                    updateContact.put("relationship_image_id", vo.getRelationship_image_id());
                }
                if (image != null && !image.isEmpty()) {
                    Object oldImageName = updateContact.get("image");
                    if (StringUtil.isNotBlank(oldImageName) && !oldImageName.toString().contains("default.jpg") && !StringTool.isInteger(oldImageName.toString())) {
                        //删除旧文件
                        baseBucketTool.delFile(BaseBucketTool.CONTACT_COMMON_PATH + oldImageName);
                    }
                    //生成文件名并上传
                    String fileName = BaseBucketTool.createFileNameToJpg();
                    baseBucketTool.upload(BaseBucketTool.CONTACT_COMMON_PATH + fileName, image, 1);
                    updateContact.put("image", fileName);
                    res.put("avator", baseBucketTool.getDOMAIN() + BaseBucketTool.CONTACT_COMMON_PATH + fileName);
                }
                deviceContactMap.put(vo.getId(),updateContact);
                device.setContactMap(deviceContactMap);
                Update updateDevice = new Update();
                updateDevice.set("c", device.getContactMap());
                if (isSerialNumNull(device)) {
                    //更新设备绑定人（家庭成员的编号）
                    int index = updateDeviceUserSerialNo(device, devUserMap, updateDevice);
                    //更新设备联系人的编号
                    updeteDeviceContactSerialNo(device, deviceContactMap, index, updateDevice);
                }
                //更新设备信息
                //this.updateById(imei, new Update().set("c", device.getContactMap()));
                this.updateById(imei, updateDevice);
                //发送kafka
                JSONObject kafkaJson = new JSONObject();
                updateContact = device.getContactMap().get(vo.getId());
                kafkaJson.put("serialNum", updateContact.get("serialNum").toString());
                kafkaJson.put("name", updateContact.get("name").toString());
                kafkaJson.put("phone", updateContact.get("phone").toString());
                if (ObjectUtils.isNotEmpty(updateContact.get("image"))) {
                    String fileName = updateContact.get("image").toString();
                    kafkaJson.put("avator", baseBucketTool.getDOMAIN() + BaseBucketTool.DEVICE_COMMON_PATH + fileName);
                }
                kafkaService.emitDeviceDemand(imei, ConstKafka.DEVICE_TYPE_ADD_CONTACT, kafkaJson, vo.getOpenid());
            } else {
                return ResponseMap.fail(ResponseEnum.STATUS4006.getCode(), "联系人未找到 " + vo.getId());
            }
        } else {
            return ResponseMap.fail();
        }
        return res;
    }

    /**
     * @description 添加联系人的新号码，删除联系人的旧号码
     * @author cwj
     * @param [imei, vo, updateContact, oldPhone]
     * @return void
     * @date @time 2025/6/22 17:50
     **/
    private void addAndDelContactCommand(String imei, DeviceUpdateContactReqVO vo, Map<String, Object> updateContact, String oldPhone) {
        JSONObject kafkaJson = new JSONObject();
        kafkaJson.put("name", updateContact.get("name").toString());
        kafkaJson.put("phone", updateContact.get("phone").toString());
        if (ObjectUtils.isNotEmpty(updateContact.get("image")) && !StringTool.isInteger(updateContact.get("image").toString())) {
            String fileName = updateContact.get("image").toString();
            kafkaJson.put("avator",baseBucketTool.getDOMAIN() + BaseBucketTool.DEVICE_COMMON_PATH + fileName);
        }
        kafkaService.emitDeviceDemand(imei, ConstKafka.DEVICE_TYPE_ADD_NEW_CONTACT, kafkaJson, vo.getOpenid());
        //延时指定时间
        delayedTime(300);
        //删除旧电话号码
        kafkaJson.remove("name");
        if(ObjectUtils.isNotEmpty(kafkaJson.get("avator"))) {
            kafkaJson.remove("avator");
        }
        kafkaJson.put("phone", oldPhone);
        kafkaService.emitDeviceDemand(imei, ConstKafka.DEVICE_TYPE_DEL_NEW_CONTACT, kafkaJson, vo.getOpenid());
    }


    /**
     * @description 程序延时指定时间
     * @author cwj
     * @param [millSecond]
     * @return void
     * @date @time 2025/6/22 17:47
     **/
    public void delayedTime(int millSecond) {
        try {
            if (Thread.currentThread().isInterrupted()) {
                log.error("线程已中断状态，跳过sleep");
            } else {
                log.info("程序睡眠300ms......");
                TimeUnit.MILLISECONDS.sleep(millSecond);
            }
        } catch (InterruptedException e){
            log.error("程序睡眠出现中断，");
            Thread.currentThread().interrupt();
        }
    }


    /**
     * @description 新版微聊协议发送更新联系人的指令
     * @author cwj
     * @param [imei, openid, image, relationshipChange, name, phone, fileName]
     * @return void
     * @date @time 2025/6/22 16:59
     **/
    private void sendUpdateContactCommand(String imei, String openid, MultipartFile image, boolean relationshipChange, Object name,Object phone,Object fileName) {
        JSONObject kafkaJson = new JSONObject();
        if(relationshipChange) {
            kafkaJson.put("name", name.toString());
            kafkaJson.put("phone", phone.toString());
            kafkaService.emitDeviceDemand(imei, ConstKafka.DEVICE_TYPE_UPDATE_NEW_CONTACT_NAME, kafkaJson, openid);
        }
        if (image != null && !image.isEmpty()) {
            if(relationshipChange) {
                kafkaJson.remove("name");
                //延时指定时间后再发送新的指令
                delayedTime(300);
            } else {
                kafkaJson.put("phone", phone.toString());
            }
            if (ObjectUtils.isNotEmpty(fileName) && !StringTool.isInteger(fileName.toString())) {
                kafkaJson.put("avator", baseBucketTool.getDOMAIN() + BaseBucketTool.DEVICE_COMMON_PATH + fileName);
            }
            kafkaService.emitDeviceDemand(imei, ConstKafka.DEVICE_TYPE_UPDATE_NEW_CONTACT_AVATOR, kafkaJson, openid);
        }
    }

    /**
     * @description 更新用户关联设备信息，更新设备联系人信息
     * @author cwj
     * @param [imei, image, updateDevice, account, userDeviceMaps, usr_thisDev, updateAccount]
     * @return void
     * @date @time 2025/6/22 16:07
     **/
    private void updateAccountAndDevice(String imei, MultipartFile image, Update updateDevice, Account account, Map<String, Map<String, Object>> userDeviceMaps, Map<String, Object> usr_thisDev, Update updateAccount) {
        //更新设备的绑定关系或联系人的信息
        this.updateById(imei, updateDevice);
        if (image != null && !image.isEmpty()) {
            String oldImageName = account.getImage();
            if (StringUtil.isNotBlank(oldImageName) && !oldImageName.contains("default.jpg") && !StringTool.isInteger(oldImageName)) {
                //删除旧文件
                baseBucketTool.delFile(BaseBucketTool.ACCOUNT_COMMON_PATH + oldImageName);
            }
            //生成文件名并上传
           /* String fileName = BaseBucketTool.createFileNameToJpg();
            baseBucketTool.upload(BaseBucketTool.ACCOUNT_COMMON_PATH + fileName, image, 1);
            updateAccount.set("image", fileName);*/
        }
        //更新用户绑定设备的信息
        userDeviceMaps.put(imei, usr_thisDev);
        updateAccount.set("d", userDeviceMaps);
        accountService.updateById(account.getId(), updateAccount);
    }

    /**
     * @description 更新联系人的编码
     * @author cwj
     * @param [device, index, updateDevice]
     * @return void
     * @date @time 2025/6/11 15:30
     **/
    private static int updeteDeviceContactSerialNo(Device device, Map<String, Map<String, Object>> devContactMap, int index, Update updateDevice) {
        Map<String, Map<String, Object>> deviceContactMap = new HashMap<>();
        List<Map<String, Object>> contactMapList = new ArrayList<>();
        if(ObjectUtils.isNotEmpty(devContactMap)) {
            for (Map.Entry<String, Map<String, Object>> entry : devContactMap.entrySet()) {
                Map<String, Object> contactMapValue = entry.getValue();
                contactMapValue.put("id",entry.getKey());
                contactMapList.add(contactMapValue);
            }
        }
        if(CollectionUtils.isNotEmpty(contactMapList)) {
            CollectionUtil.sortDouble(contactMapList, "t", 2);
            if(ObjectUtils.isEmpty(device.getUserMap())) {
                for(int i = 0; i< contactMapList.size(); i++){
                    index += i+1;
                    Map<String, Object> contactMapValue = contactMapList.get(i);
                    String key = (String) contactMapValue.get("id");
                    //加上编号
                    contactMapValue.put("serialNum", index);
                    contactMapValue.remove("id");
                    deviceContactMap.put(key,contactMapValue);
                }
            } else {
                for(int i = 0; i< contactMapList.size(); i++) {
                    Map<String, Object> contactMapValue = contactMapList.get(i);
                    String key = (String) contactMapValue.get("id");
                    boolean isContactExists = false;
                    Integer existsSerialNum =  null;
                    for (Map.Entry<String, Map<String, Object>> userMap : device.getUserMap().entrySet()) {
                        Map<String, Object> userMapValue = userMap.getValue();
                        if(userMapValue.get("phone").toString().equals(contactMapValue.get("phone").toString())) {
                            isContactExists = true;
                            if(ObjectUtils.isNotEmpty("serialNum")) {
                                existsSerialNum = Integer.valueOf(userMapValue.get("serialNum").toString());
                            }
                            break;
                        }
                    }
                    if(isContactExists && ObjectUtils.isNotEmpty(existsSerialNum)) {
                        //加上编号
                        contactMapValue.put("serialNum", existsSerialNum);
                    } else {
                        index += i+1;
                        //加上编号
                        contactMapValue.put("serialNum", index);
                    }
                    contactMapValue.remove("id");
                    deviceContactMap.put(key,contactMapValue);
                }
            }
            //更新设备联系人的编码信息
            device.setContactMap(deviceContactMap);
            updateDevice.set("c",deviceContactMap);
        }
        return index;
    }

    /**
     * @description 更新设备绑定人的编号（家庭成员）
     * @author cwj
     * @param [device, updateDevice]
     * @return int
     * @date @time 2025/6/11 14:24
     **/
    private int updateDeviceUserSerialNo(Device device,Map<String, Map<String, Object>> deviceUserMap, Update updateDevice) {
        List<Map<String, Object>> memberList = new ArrayList<>();
        //按照下发顺序更新编号
        Map<String, Map<String, Object>> userMap = new HashMap<>();
        if(ObjectUtils.isNotEmpty(deviceUserMap)) {
            for (Map.Entry<String, Map<String, Object>> entry : deviceUserMap.entrySet()) {
                Map<String, Object> userMapValue = entry.getValue();
                userMapValue.put("id",entry.getKey());
                memberList.add(userMapValue);
            }
        }
        if(CollectionUtils.isNotEmpty(memberList)) {
            CollectionUtil.sortDouble(memberList, "t", 2);
            for(int i = 0; i< memberList.size(); i++){
                Map<String, Object> userMapValue = memberList.get(i);
                String key = (String) userMapValue.get("id");
                //加上编号
                userMapValue.put("serialNum",i+1);
                userMapValue.remove("id");
                userMap.put(key,userMapValue);
            }
            //更新设备绑定人的编号信息（家庭成员）
            device.setUserMap(userMap);
            updateDevice.set("u", userMap);
        }
        return memberList.size();
    }

    /**
     * 删除通讯录
     *
     * @param imei
     * @param vo
     * @time: 2020/12/4 14:36
     * @author: Rock
     * @version 1.0
     */
    public ResponseMap delContact(String imei, IdParamReqVO vo, Boolean isInternal) {
        //删除通讯录，只有管理员身份才可以修改
        if(!accountService.checkAccountIsAdminWithImei(vo.getOpenid(), imei)){
            //仅限于管理员操作  API.request.onlyAdminOperation
            return ResponseMap.fail(ResponseEnum.STATUS403.getCode(), "API.request.onlyAdminOperation");
        }
        if (!isInternal){
            //频繁操作检查
            if (StringUtil.isNotBlank(redisClusterService.get(CacheEnum.FREQUENT.getKey() + imei))) {
                return ResponseMap.fail(ResponseEnum.STATUS500.getCode(), "频繁操作,请稍后再试");
            } else {
                redisClusterService.setex(CacheEnum.FREQUENT.getKey() + imei, CacheEnum.FREQUENT.getExpire(), vo.getOpenid());
            }
        }
        Device device = this.findById(imei);
        if (device == null) {
            log.error("Device is null. _id={}", imei);
            return ResponseMap.fail(ResponseEnum.STATUS2001.getCode(), ResponseEnum.STATUS2001.getMsg(), imei);
        }
        if (Const.INT_1.equals(device.getIsIOTCard())) {
            if(device.getWatchCustomFunction().contains("IOTCard:RJ")){
                IotCardInfo iotCardInfo = iotCardInfoService.findById(device.getIccid());
                if(iotCardInfo == null) {
                    return ResponseMap.fail("miss iotCardInfo");
                }
                //物联网卡 的通讯录ID 也是 手机号
                Object delRes = RuiJiIOTUtil.doRJCardWhiteList(device.getIccid(), vo.getId(), false);
                if (delRes instanceof Boolean) {
                    //成功, 删掉
                    iotCardInfo.getContactMap().remove(vo.getId());
                    iotCardInfoService.save(iotCardInfo);
                }else{
                    log.info("瑞集 物联网卡 删除白名单失败 imei:{} iccid:{} res:{}", imei, device.getIccid(), delRes);
                    return ResponseMap.fail((String)delRes);
                }
            }
//            return ResponseMap.fail(ResponseEnum.STATUS500.getCode(), "物联网卡不支持删除通讯录操作,如需删除请联系客服人员处理");
        } else {
            //检查家庭成员和联系人是否存在，不存在则，按照之前业务发送指令的顺序生成序列号
            Update updateDevice = new Update();
            if(isSerialNumNull(device)) {
                //更新设备绑定人（家庭成员的编号）
                int index = updateDeviceUserSerialNo(device,device.getUserMap(), updateDevice);
                //更新设备联系人的编号
                updeteDeviceContactSerialNo(device,device.getContactMap(), index, updateDevice);
            }
            Map<String, Object> delContact = CollectionUtil.removeMapKeyData(device.getContactMap(), vo.getId());
            if (delContact != null) {
                updateDevice.set("c",device.getContactMap());
                //this.updateById(imei, new UpdateVO().setMap("c", device.getContactMap()));
                //删除image文件,是整数则为系统的图片，不能删除
                if (StringUtil.isNotBlank(delContact.get("image")) && !StringTool.isInteger("" + delContact.get("image"))) {
                    //删除文件
                    baseBucketTool.delFile(BaseBucketTool.CONTACT_COMMON_PATH + delContact.get("image").toString());
                }
                if(ObjectUtils.isNotEmpty(delContact.get("serialNum"))) {
                    JSONObject kafkaJson = new JSONObject();
                    kafkaJson.put("serialNum",delContact.get("serialNum").toString());
                    log.info("删除联系人的编号为：{}",delContact.get("serialNum"));
                    kafkaService.emitDeviceDemand(imei, ConstKafka.DEVICE_TYPE_DEL_CONTACT, kafkaJson, vo.getOpenid());
                    //更新操作,无编号则更新编号，删除这个联系人
                    this.updateById(imei, updateDevice);
                    updateCacheMaxSerialNum(device);
                }
            }
        }
        //发送kafka
        /*JSONObject kafkaJson = new JSONObject();
        kafkaJson.put("handleFlag", 2);
        kafkaJson.put("id", vo.getId());
        kafkaService.emitDeviceDemand(imei, ConstKafka.DEVICE_TYPE_Contact, kafkaJson, vo.getOpenid());*/
        return ResponseMap.success();
    }

    /**
     * @description 更新设备缓存联系人最大编号的大小
     * @author cwj
     * @param [device]
     * @return void
     * @date @time 2025/6/19 11:25
     **/
    private void updateCacheMaxSerialNum(Device device){
        //修改缓存的联系人编号
        Integer maxSerialNum = 0;
        Integer cacheMaxSerialNum = null;
        if(ObjectUtils.isNotEmpty(device.getUserMap())) {
            for (Map.Entry<String, Map<String, Object>> entry : device.getUserMap().entrySet()) {
                Map<String, Object> userMapValue = entry.getValue();
                Integer currentSn = Integer.valueOf(userMapValue.get("serialNum").toString());
                if ((maxSerialNum - currentSn) < 0) {
                    maxSerialNum = currentSn;
                }
            }
        }
        if(ObjectUtils.isNotEmpty(device.getContactMap())) {
            for (Map.Entry<String, Map<String, Object>> entry : device.getContactMap().entrySet()) {
                Map<String, Object> contactMapValue = entry.getValue();
                Integer currentSn = Integer.valueOf(contactMapValue.get("serialNum").toString());
                if((maxSerialNum - currentSn) < 0) {
                    maxSerialNum = currentSn;
                }
            }
        }
        //检查缓存是否存在
        String maxSerialNumRedisValue = redisFilterService.get(device.getId()+Constant.MAX_SERIAL_NUM_KEY_POSTFIX);
        if(StringUtils.isNotEmpty(maxSerialNumRedisValue)){
            cacheMaxSerialNum = Integer.valueOf(maxSerialNumRedisValue);
            if(cacheMaxSerialNum > maxSerialNum) {
                cacheMaxSerialNum = maxSerialNum;
                redisFilterService.set(device.getId()+Constant.MAX_SERIAL_NUM_KEY_POSTFIX,cacheMaxSerialNum.toString());
            }
        } else {
            cacheMaxSerialNum = maxSerialNum;
            redisFilterService.set(device.getId()+Constant.MAX_SERIAL_NUM_KEY_POSTFIX,cacheMaxSerialNum.toString());
        }
    }

    /**
     * 删除多个设备通讯录记录，作废该方法
     *
     * @param imei
     * @param vo
     * @time: 2021/2/7 10:13
     * @author: Rock
     * @version 1.0
     */
    public ResponseMap delManyContact2(String imei, ContactIdsParamReqVO vo) {
        //删除多个设备通讯录记录，只有管理员身份才可以修改
        if(!accountService.checkAccountIsAdminWithImei(vo.getOpenid(), imei)){
            //仅限于管理员操作  API.request.onlyAdminOperation
            return ResponseMap.fail(ResponseEnum.STATUS403.getCode(), "API.request.onlyAdminOperation");
        }
        //频繁操作检查
        if (StringUtil.isNotBlank(redisClusterService.get(CacheEnum.FREQUENT.getKey() + imei))) {
            return ResponseMap.fail(ResponseEnum.STATUS500.getCode(), "频繁操作,请稍后再试");
        } else {
            redisClusterService.setex(CacheEnum.FREQUENT.getKey() + imei, CacheEnum.FREQUENT.getExpire(), vo.getOpenid());
        }
        Device device = this.findById(imei);
        if (device == null) {
            log.error("Device is null. _id={}", imei);
            return ResponseMap.fail(ResponseEnum.STATUS2001.getCode(), ResponseEnum.STATUS2001.getMsg(), imei);
        }
//        if (Const.INT_1.equals(device.getIsIOTCard())) {
//            return ResponseMap.fail(ResponseEnum.STATUS500.getCode(), "物联网卡不支持删除通讯录操作,如需删除请联系客服人员处理");
//        }

        JSONArray idArr = JSON.parseArray(vo.getContactIds());

        if (Const.INT_1.equals(device.getIsIOTCard())) {
            if (idArr.size() > 1) {
                return ResponseMap.fail(ResponseEnum.STATUS403.getCode(), "物联网卡不支持批量删除通讯录操作");
            }

            if(device.getWatchCustomFunction().contains("IOTCard:RJ")){
                IdParamReqVO aVo = new IdParamReqVO();
                aVo.setOpenid(vo.getOpenid());
                aVo.setAccesstoken(vo.getAccesstoken());
                aVo.setId(idArr.getString(0));
                return delContact(imei, aVo, true);
            }
            return ResponseMap.fail(ResponseEnum.STATUS403.getCode(), "物联网卡不支持删除通讯录操作,如需删除请联系客服人员处理");
        }

        boolean needUpdateC = false;
        List<String> delImage = new ArrayList<>();
        //获取删除数据前电话本的编号，按顺序组装编号
        String delContactNos = obtainDelContactNo(idArr,device.getUserMap(),device.getContactMap());
        for (int i = 0; i < idArr.size(); i++) {
            String itemId = idArr.getString(i);
            //如果id的长度和 openid的长度相同,那么是家庭成员 (普通通讯录的id 是8位)
            if(idArr.size() == 1 && itemId.length() == vo.getOpenid().length()){
                //是家庭成员, 那么删除家庭成员，构建删除家庭成员的请求体
                DeviceDelMemberReqVO delMemberReqVO = new DeviceDelMemberReqVO();
                delMemberReqVO.setId(itemId);
                delMemberReqVO.setOpenid(vo.getOpenid());
                delMemberReqVO.setImei(imei);
                //调用类型 0:自己解绑 1:被管理员在通讯录删除联系人解绑
                delMemberReqVO.setCallType(1); //通讯录删除
                log.info("管理员删除家庭成员 delMemberReqVO:{}",delMemberReqVO);
                ResponseMap tempRes = this.delMember(delMemberReqVO);
                if (!tempRes.get("code").toString().equals("0")){
                    return ResponseMap.fail();
                }
            } else {
                Map<String, Object> delContact = CollectionUtil.removeMapKeyData(device.getContactMap(), itemId);
                if (delContact != null) {
                    //删除image文件
                    if (StringUtil.isNotBlank(delContact.get("image"))) {
                        delImage.add(BaseBucketTool.CONTACT_COMMON_PATH + delContact.get("image").toString());
                    }
                    needUpdateC = true;
                }
            }
        }
        if(needUpdateC) {
            //更新操作
            this.updateById(imei, new UpdateVO().setMap("c", device.getContactMap()));
            //更新完数据库再删除文件
            for (String image : delImage) {
                //删除文件
                baseBucketTool.delFile(image);
            }
        }
        //发送kafka
        JSONObject kafkaJson = new JSONObject();
        kafkaJson.put("handleFlag", 2);
        kafkaJson.put("ContactIds", vo.getContactIds());
        kafkaJson.put("delContactNos",delContactNos);
        kafkaService.emitDeviceDemand(imei, ConstKafka.DEVICE_TYPE_Contact, kafkaJson, vo.getOpenid());
        return ResponseMap.success();
    }

    /**
     * @description 删除一个或多个联系人
     * @author cwj
     * @param [imei, vo]
     * @return com.iot08.common.utils.response.ResponseMap
     * @date @time 2025/6/19 14:51
     **/
    public ResponseMap delManyContact(String imei, ContactIdsParamReqVO vo) {
        //删除多个设备通讯录记录，只有管理员身份才可以修改
        if(!accountService.checkAccountIsAdminWithImei(vo.getOpenid(), imei)){
            //仅限于管理员操作  API.request.onlyAdminOperation
            return ResponseMap.fail(ResponseEnum.STATUS403.getCode(), "API.request.onlyAdminOperation");
        }
        //频繁操作检查
        if (StringUtil.isNotBlank(redisClusterService.get(CacheEnum.FREQUENT.getKey() + imei))) {
            return ResponseMap.fail(ResponseEnum.STATUS500.getCode(), "频繁操作,请稍后再试");
        } else {
            redisClusterService.setex(CacheEnum.FREQUENT.getKey() + imei, CacheEnum.FREQUENT.getExpire(), vo.getOpenid());
        }
        Device device = this.findById(imei);
        if (device == null) {
            log.error("Device is null. _id={}", imei);
            return ResponseMap.fail(ResponseEnum.STATUS2001.getCode(), ResponseEnum.STATUS2001.getMsg(), imei);
        }
        JSONArray idArr = JSON.parseArray(vo.getContactIds());
        for (int i = 0; i < idArr.size(); i++) {
            String itemId = idArr.getString(i);
            //如果id的长度和 openid的长度相同,那么是家庭成员 (普通通讯录的id 是8位)
            if(idArr.size() == 1 && itemId.length() == vo.getOpenid().length()){
                //是家庭成员, 那么删除家庭成员，构建删除家庭成员的请求体
                DeviceDelMemberReqVO delMemberReqVO = new DeviceDelMemberReqVO();
                delMemberReqVO.setId(itemId);
                delMemberReqVO.setOpenid(vo.getOpenid());
                delMemberReqVO.setImei(imei);
                //调用类型 0:自己解绑 1:被管理员在通讯录删除联系人解绑
                delMemberReqVO.setCallType(1); //通讯录删除
                log.info("管理员删除家庭成员 delMemberReqVO:{}",delMemberReqVO);
                ResponseMap tempRes = this.delMember(delMemberReqVO);
                if (!tempRes.get("code").toString().equals("0")){
                    return ResponseMap.fail();
                }
            } else {
                //删除的是联系人
                Update updateDevice = new Update();
                if (isSerialNumNull(device)) {
                    //更新设备绑定人（家庭成员的编号）
                    int index = updateDeviceUserSerialNo(device, device.getUserMap(), updateDevice);
                    //更新设备联系人的编号
                    updeteDeviceContactSerialNo(device, device.getContactMap(), index, updateDevice);
                }
                //检查家庭成员和联系人是否存在，不存在则，按照之前业务发送指令的顺序生成序列号
                Map<String, Object> delContact = CollectionUtil.removeMapKeyData(device.getContactMap(), itemId);
                if (delContact != null) {
                    updateDevice.set("c", device.getContactMap());
                    //this.updateById(imei, new UpdateVO().setMap("c", device.getContactMap()));
                    //删除image文件,是整数则为系统的图片，不能删除
                    if (StringUtil.isNotBlank(delContact.get("image")) && !StringTool.isInteger(delContact.get("image").toString())) {
                        //删除文件
                        baseBucketTool.delFile(BaseBucketTool.CONTACT_COMMON_PATH + delContact.get("image").toString());
                    }
                    if (ObjectUtils.isNotEmpty(delContact.get("serialNum"))) {
                        JSONObject kafkaJson = new JSONObject();
                        kafkaJson.put("serialNum", delContact.get("serialNum").toString());
                        log.info("删除联系人的编号为：{}", delContact.get("serialNum"));
                        kafkaService.emitDeviceDemand(imei, ConstKafka.DEVICE_TYPE_DEL_CONTACT, kafkaJson, vo.getOpenid());
                        //更新操作,无编号则更新编号，删除这个联系人
                        this.updateById(imei, updateDevice);
                        updateCacheMaxSerialNum(device);
                    } else {
                        return ResponseMap.fail(ResponseEnum.STATUS400.getCode(), "被删除人的联系人编号不存在");
                    }
                }
               /* } else {
                    //检查家庭成员和联系人是否存在，不存在则，按照之前业务发送指令的顺序生成序列号
                    Map<String, Object> delContact = CollectionUtil.removeMapKeyData(device.getContactMap(), itemId);
                    if (delContact != null) {
                        updateDevice.set("c", device.getContactMap());
                        //更新操作,无编号则更新编号，删除这个联系人
                        this.updateById(imei, updateDevice);
                        //删除image文件,是整数则为系统的图片，不能删除
                        if (StringUtil.isNotBlank(delContact.get("image")) && !StringTool.isInteger(delContact.get("image").toString())) {
                            //删除文件
                            baseBucketTool.delFile(BaseBucketTool.CONTACT_COMMON_PATH + delContact.get("image").toString());
                        }
                        JSONObject kafkaJson = new JSONObject();
                        kafkaJson.put("phone", delContact.get("phone").toString());
                        kafkaService.emitDeviceDemand(imei, ConstKafka.DEVICE_TYPE_DEL_NEW_CONTACT, kafkaJson, vo.getOpenid());
                    }
                }*/
            }
        }
        return ResponseMap.success();
    }
    
    /**
     * @description 获取删除联系人上次设置的编号顺序
     * @author Rock
     * @param [idArr, userMap, contactMap]
     * @return java.lang.String
     * @date @time 2025/2/16 16:35
     **/
    public String obtainDelContactNo(JSONArray idArr,Map<String, Map<String, Object>> userMap,Map<String, Map<String, Object>> contactMap){
        //查询上次设置联系人编号的序号
        List<Map<String, Object>> contactList = new ArrayList<>();
        if (CollectionUtil.isNotEmpty(userMap)) {
            for (Map.Entry<String, Map<String, Object>> entry : userMap.entrySet()) {
                JSONObject tempJSONOB = new JSONObject(entry.getValue());
                if(!StringUtil.isNumeric(tempJSONOB.getString("phone"))){
                    continue;
                }
                Map<String, Object> temp = new HashMap<>();
                temp.put("id", entry.getKey());
                temp.put("openid", entry.getKey());
                contactList.add(temp);
            }
        }
        if (CollectionUtil.isNotEmpty(contactMap)) {
            for (Map.Entry<String, Map<String, Object>> entry : contactMap.entrySet()) {
                JSONObject tempJSONOB = new JSONObject(entry.getValue());
                log.info("取出的联系人对象：{}",tempJSONOB);
                if(tempJSONOB.containsKey("openid")){
                    //如果通讯录里有的 openid 的成员的, 不添加到dataList了, 会和上面的冲突
                    continue;
                }
                if(!StringUtil.isNumeric(tempJSONOB.getString("phone"))){
                    continue;
                }
                Map<String, Object> temp = new HashMap<>();
                temp.put("id", entry.getKey());
                temp.put("phone", tempJSONOB.getString("phone"));
                contactList.add(temp);
            }
        }
        String delContactNos = "";
        for(int i=0;i<contactList.size();i++){
            for(int j=0;j<idArr.size();j++){
                String itemId = idArr.getString(j);
                if(ObjectUtils.isNotEmpty(contactList.get(i).get("id"))){
                    String id = contactList.get(i).get("id").toString();
                    if(id.equals(itemId)) {
                        int no = i+1;
                        if(StringUtils.isEmpty(delContactNos)){
                            delContactNos += ""+no;
                        } else {
                            delContactNos += ","+no;
                        }
                    }
                }
            }
        }
        if(StringUtils.isNotEmpty(delContactNos)){
            delContactNos = "["+delContactNos+"]";
        }
        return delContactNos;
    }

    /**
     * 批量添加设备多个通讯录记录
     *
     * @param imei
     * @param vo
     * @param image
     * @time: 2021/1/12 17:41
     * @author: Rock
     * @version 1.0
     */
    public ResponseMap addManycontact(String imei, DeviceAddManyContactReqVO vo, MultipartFile image) throws IOException {
        Device device = this.findById(imei);
        if (device == null) {
            log.error("Device is null. _id={}", imei);
            return ResponseMap.fail(ResponseEnum.STATUS2001.getCode(), ResponseEnum.STATUS2001.getMsg(), imei);
        }
        ResponseMap res = ResponseMap.success();
        int missingExistsContact = 0;
        List<JSONObject> listJson = new ArrayList<>();
        //List<JSONObject> failListJson = new ArrayList<>();
        JSONArray contactJson = JSON.parseArray(vo.getContact_arry());
        log.info("contactJson = {}", contactJson.toJSONString());
        //去重
        Set<String> phoneSet = new HashSet<>();
        for (int i = 0; i < contactJson.size(); i++) {
            JSONObject sub = contactJson.getJSONObject(i);
            if (StringUtil.isNotBlank(sub.getString("phones"))) {
                phoneSet.add(sub.getString("phones"));
            }
        }
        //重新整理数据 倒序查找 (为实现以最后面的数据为准的需求)
        for (int i = contactJson.size() - 1; i >= 0; i--) {
            JSONObject sub = contactJson.getJSONObject(i);
            if (phoneSet.contains(sub.getString("phones"))) {
                listJson.add(0, sub);
                phoneSet.remove(sub.getString("phones"));
            }
        }
        if (Const.INT_1.equals(device.getIsIOTCard())) {
            return ResponseMap.fail(ResponseEnum.STATUS403.getCode(), "物联网卡不支持批量添加通讯录操作");
        }
//        if (Const.INT_1.equals(device.getIsIOTCard())) {
//            IotCardInfo iotCardInfo = iotCardInfoService.findById(device.getIccid());
//            if (iotCardInfo != null) {
//                //先查询白名单再添加
//                JSONObject body = CXUtil.queryCXCardWhiteList(device.getIccid());
//                if (body != null && !body.isEmpty()) {
//                    //更新在库中记录的白名单
//                    iotCardInfoService.updareContacts(iotCardInfo, body.getJSONArray("mobile"), body.getJSONArray("nick"));
//                } else {
//                    log.error("CXUtil.queryCXCardWhiteList is fail. vo={}", vo.toString());
//                }
//
//                if (iotCardInfo.getContactMap() == null) {
//                    iotCardInfo.setContactMap(new HashMap<>());
//                }
//                if (listJson.size() + iotCardInfo.getContactMap().size() >= Const.CX_NUM) {
//                    return ResponseMap.fail(ResponseEnum.STATUS500.getCode(),
//                            String.format("号码数量不能超过10个,可添加号码数为%s个", Const.CX_NUM - iotCardInfo.getContactMap().size()));
//                }
//                StringBuilder phones = new StringBuilder();
//                StringBuilder names = new StringBuilder();
//                int index = 0;
//                for (JSONObject json : listJson) {
//                    index++;
//                    boolean flag = false;
//                    if (json.getString("phone") != null) {
//                        for (Map.Entry<String, Map<String, Object>> entry : iotCardInfo.getContactMap().entrySet()) {
//                            if (json.getString("phone").equals(entry.getValue().get("phone"))) {
//                                failListJson.add(json);
//                                flag = true;
//                                break;
//                            }
//                        }
//                        if (flag) {
//                            continue;
//                        }
//                        phones.append(json.getString("phone"));
//                        names.append(json.getString("name"));
//                        if (index != listJson.size()) {
//                            phones.append(json.getString(","));
//                            names.append(json.getString(","));
//                        }
//                    }
//                }
//                if (StringUtil.isNotBlank(phones)) {
//                    if (StringUtil.isNotBlank(redisClusterService.get(device.getIccid()))) {
//                        return ResponseMap.fail(ResponseEnum.STATUS500.getCode(), "添加物联网白名单操作频繁,请稍后再试");
//                    }
//                    //先查询白名单再添加
//                    boolean addCXCardWhite = CXUtil.addCXCardWhiteList(device.getIccid(), names.toString(), phones.toString());
//                    if (addCXCardWhite) {
//                        redisFilterService.setex(device.getIccid(), 30, "addWhite");
//                        iotCardInfoService.updareContacts(iotCardInfo, vo.getOpenid(), listJson);
//                        res.put("missing_exists_contact", failListJson);
//                        //发送kafka
//                        JSONObject kafkaJson = new JSONObject();
//                        kafkaJson.put("handleFlag", 1);
//                        kafkaService.emitDeviceDemand(imei, ConstKafka.DEVICE_TYPE_Contact, kafkaJson, vo.getOpenid());
//                    }
//                }
//            }
//            return res;
//        }
        if (device.getContactMap() == null) {
            device.setContactMap(new HashMap<>());
        }
        // 通讯录和家庭成员合起来超过 DEVICE_OPENID_NUM 限定次数(50次?)
        int num = 0;
        if(device.getUserMap() != null){
            num = device.getUserMap().size();
        }
        int sumNum = device.getContactMap().size() + contactJson.size() + num;
        //TODO 为了兼容 Python => Java 的衔接, 判断数量时需要把 通讯录 中的 家庭成员(有openid)的数量滤掉,防止重复
        int haveOpenidNum = 0;
        for (String key : device.getContactMap().keySet()) {
            Map<String, Object> itemMap = device.getContactMap().get(key);
            if (itemMap.containsKey("openid")) {
                haveOpenidNum += 1;
            }
        }
        sumNum = sumNum - haveOpenidNum;
        if (sumNum > Constant.DEVICE_OPENID_NUM) {
            log.error("通讯录的号码 + 家庭成员的 数量不能超过{}个, imei={}", Constant.DEVICE_OPENID_NUM, imei);
            return ResponseMap.fail(ResponseEnum.STATUS4010.getCode(), "API.request.contantNumLimit", Constant.DEVICE_OPENID_NUM);
        }
        //检查设备绑定人（家庭成员）及设备联系人是否没有编码,批量更新
        boolean isSnNull = isSerialNumNull(device);
        //是否为旧版微聊
        //boolean isOldWechat = ObjectUtils.isEmpty(device.getIsNewWechatProtocol()) || !device.getIsNewWechatProtocol().equals(1);
        String maxSerialNumRedisValue = redisFilterService.get(imei+Constant.MAX_SERIAL_NUM_KEY_POSTFIX);
        List<Integer> hasDelSerialNum = new ArrayList<>();
        List<Map<String, Object>> contactMapList = new ArrayList<>();
        Integer maxSerialNum = null;
        if(StringUtils.isNotEmpty(maxSerialNumRedisValue)){
            maxSerialNum = Integer.valueOf(maxSerialNumRedisValue);
        }
        //获取当前联系人的编号，并将没有联系人编号的数据更新
        maxSerialNum = obtainCurrentSerialNum(isSnNull, device, maxSerialNum, hasDelSerialNum);
        for (int i = 0; i < contactJson.size(); i++) {
            boolean flag = false;
            String ph = contactJson.getJSONObject(i).getString("phone");
            if (StringUtil.isNotBlank(ph)) {
                for (Map.Entry<String, Map<String, Object>> entry : device.getContactMap().entrySet()) {
                    if (ph.equals(entry.getValue().get("phone"))) {
                        flag = true;
                        break;
                    }
                }
                //同时也得检测设备的家庭成员号码是否重复
                if (device.getUserMap() != null) {
                    for (Map.Entry<String, Map<String, Object>> entry : device.getUserMap().entrySet()) {
                        if (ph.equals(entry.getValue().get("phone"))) {
                            flag = true;
                            break;
                        }
                    }
                } else {
                    log.error("imei:{} device.getUserMap()为空, 有异常,没有绑定用户怎么添加通讯录?", device.getId());
                }
                if (flag) {
                    //号码存在则不添加
                    continue;
                }
                String cid = RandomUtil.getRandomStr(8);
                Map<String, Object> contactMap = new HashMap<>();
                contactMap.put("t", DateUtil.nowTimestampToLong());
                contactMap.put("c", vo.getOpenid());
                contactMap.put("name", contactJson.getJSONObject(i).get("name"));
                contactMap.put("phone", ph);
                if(CollectionUtils.isEmpty(hasDelSerialNum)) {
                    maxSerialNum++;
                    contactMap.put("serialNum",maxSerialNum);
                } else {
                    contactMap.put("serialNum", hasDelSerialNum.get(0));
                    hasDelSerialNum.remove(0);
                }
                if (image != null && !image.isEmpty()) {
                    //生成文件名并上传
                    String fileName = BaseBucketTool.createFileNameToJpg();
                    baseBucketTool.upload(BaseBucketTool.CONTACT_COMMON_PATH + fileName, image, 1);
                    contactMap.put("image", fileName);
                    //res.put("avator", baseBucketTool.getDOMAIN() + BaseBucketTool.DEVICE_COMMON_PATH + fileName);
                }
                contactMapList.add(contactMap);
                device.getContactMap().put(cid, contactMap);
                //res.put("id", cid);
            }
        }
        //更新操作
        this.updateById(imei, new Update().set("c", device.getContactMap()));
        Integer index = 0;
        //批量发送添加联系人指令
        for (Map<String, Object> cm : contactMapList) {
            index++;
            //发送kafka
            JSONObject kafkaJson = new JSONObject();
            kafkaJson.put("serialNum",cm.get("serialNum").toString());
            kafkaJson.put("name",cm.get("name"));
            kafkaJson.put("phone",cm.get("phone"));
            if (ObjectUtils.isNotEmpty(cm.get("image")) && !StringTool.isInteger(cm.get("image").toString())) {
                String fileName =  cm.get("image").toString();
                kafkaJson.put("avator",baseBucketTool.getDOMAIN() + BaseBucketTool.DEVICE_COMMON_PATH + fileName);
            }
            kafkaService.emitDeviceDemand(imei, ConstKafka.DEVICE_TYPE_ADD_CONTACT, kafkaJson, vo.getOpenid());
            if((index - contactMapList.size()) < 0) {
                try {
                    if (Thread.currentThread().isInterrupted()) {
                        log.error("线程已中断状态，跳过sleep");
                    } else {
                        log.info("程序睡眠1s......");
                        TimeUnit.MILLISECONDS.sleep(500);
                    }
                } catch (InterruptedException e){
                    log.error("程序睡眠出现中断，");
                    Thread.currentThread().interrupt();
                }
            }
        }
        //缓存当前最大序列号
        redisFilterService.set(imei+Constant.MAX_SERIAL_NUM_KEY_POSTFIX,maxSerialNum.toString());
        /*JSONObject kafkaJson = new JSONObject();
        kafkaJson.put("handleFlag", 1);
        kafkaService.emitDeviceDemand(imei, ConstKafka.DEVICE_TYPE_Contact, kafkaJson, vo.getOpenid());
        res.put("missing_exists_contact", missingExistsContact);*/
        res.put("missing_exists_contact", missingExistsContact);
        return res;
    }

    /**
     * @description 获取当前序列号，如果没有序列号则更新设备的序列号
     * @author cwj
     * @param [isSnNull, device, maxSerialNum, hasDelSerialNum]
     * @return java.lang.Integer
     * @date @time 2025/6/15 11:00
     **/
    private Integer obtainCurrentSerialNum(boolean isSnNull, Device device, Integer maxSerialNum, List<Integer> hasDelSerialNum) {
        if(isSnNull){
            //更新设备绑定人及设备联系人的编码
            Update updateDevice = new Update();
            //更新设备绑定人（家庭成员的编号）
            int index = updateDeviceUserSerialNo(device, device.getUserMap(), updateDevice);
            //更新设备联系人的编号
            index = updeteDeviceContactSerialNo(device, device.getContactMap(), index, updateDevice);
            maxSerialNum = index;
            //更新设备家庭成员及联系人的序列号
            this.updateById(device.getId(),updateDevice);
        } else {
            //找出其中漏掉的编号（之前删除过联系人，或者解绑过用户，编号就会出现空缺或不连贯）
            List<Map<String, Object>> allContactList = new ArrayList<>();
            //取所有联系人的编号（家庭成员+普通联系人）
            assembleAllContactData(device,allContactList);
            if(CollectionUtils.isNotEmpty(allContactList)) {
                //按编号从小到达顺序进行排序
                CollectionUtil.sortByKeyType(allContactList, "serialNum", 2);
                if(ObjectUtils.isNotEmpty(allContactList.get(allContactList.size() -1).get("serialNum"))) {
                    //存序号最大的
                    maxSerialNum = Integer.valueOf(allContactList.get(allContactList.size() -1).get("serialNum").toString());
                }
                for(int i=0;i<allContactList.size();i++) {
                    Map<String,Object> map = allContactList.get(i);
                    if(ObjectUtils.isNotEmpty(map.get("serialNum"))) {
                        Integer serialNum = (Integer) map.get("serialNum");
                        if(!serialNum.equals(i + 1)) {
                            if(i == 0) {
                                hasDelSerialNum.add(i+1);
                            } else {
                                //查找前面的编号中是否存在等于i+1的
                                boolean hasExistsSerialNum = false;
                                for(int j=0;j<i;j++) {
                                    Map<String,Object> tempMap = allContactList.get(j);
                                    if(ObjectUtils.isNotEmpty(tempMap.get("serialNum"))){
                                        Integer tempSerialNum = (Integer) tempMap.get("serialNum");
                                        if(tempSerialNum.equals(i+1)){
                                            hasExistsSerialNum = true;
                                            break;
                                        }
                                    }
                                }
                                if(!hasExistsSerialNum) {
                                    hasDelSerialNum.add(i+1);
                                }
                            }
                        }
                    }
                }
                if(CollectionUtils.isEmpty(hasDelSerialNum)) {
                    maxSerialNum = allContactList.size();
                } else {
                    if(ObjectUtils.isEmpty(maxSerialNum)){
                        maxSerialNum = allContactList.size()+hasDelSerialNum.size();
                    }
                }
            } else {
                maxSerialNum = 0;
            }
        }
        return maxSerialNum;
    }


    /**
     *  前端 根据 isAddIOTCard==0 的属性 才会调用此接口
     *  把管理者/关注者的 手机号添加至 卡商系统
     * @param imei 设备IMEI
     * @param id 通讯录ID (一般是用户的Openid)
     * @return
     */
    public ResponseMap addMemberToIOTCard(String imei, String id, String opOpenid){
        ResponseMap res = ResponseMap.success();
        Device device = this.findById(imei);
        IotCardInfo iotCardInfo = iotCardInfoService.findById(device.getIccid());
        if(iotCardInfo == null){
            return ResponseMap.fail("miss iotCardInfo");
        }
        //使用物联网卡记录的 通讯录
        Map<String, Map<String, Object>> contactMap = iotCardInfo.getContactMap();
        //家庭成员
        /*
                "wxsp_o5gqM65ei-zkgi3SbPAr5zqu_Wg4" : {
                        "image" : 9,
                        "c" : "wxsp_o5gqM65ei-zkgi3SbPAr5zqu_Wg4",
                        "t" : 1703577840.922,
                        "phone" : "17877725428",
                        "identity" : "admin",
                        "openid" : "wxsp_o5gqM65ei-zkgi3SbPAr5zqu_Wg4",
                        "g" : "658a88f05e3a3c01f81b5f9e",
                        "name" : "钟",
                        "canVideo" : 1,
                        "relationship" : "钟",
                        "relationship_image_id" : 9
                }
        */
        Map<String, Object> userMap = device.getUserMap().get(id);
        if(userMap == null){
            return ResponseMap.fail("miss Member "+id);
        }
        String phone = userMap.get("phone").toString();


        if(contactMap.keySet().contains(phone)){
            log.info("操作者:{} phone:{} imei:{} 已经添加过白名单了,无需再次添加,请刷新", opOpenid, phone, imei);
            return ResponseMap.fail("已经添加过白名单了,无需再次添加,请刷新");
        }

        //去物联网卡运营商 添加
        Object addRes = RuiJiIOTUtil.doRJCardWhiteList(device.getIccid(), phone, true);
        if(addRes instanceof Boolean){
            //成功, 昵称 +手机号存储起来
            Map<String, Object> item = new HashMap<>();
            item.put("phone", phone);
            item.put("name", userMap.get("relationship"));
            item.put("t", DateUtil.nowTimestampToLong());
            iotCardInfo.getContactMap().put(id,item);
            iotCardInfoService.save(iotCardInfo);
            res.put("id", id);
            return res;
        }else {
            //失败, 信息直接透传前端
            return ResponseMap.fail((String)addRes);
        }
    }

    /**
     * @param imei
     * @time: 2020/12/4 16:32
     * @author: Rock
     * @version 1.0
     */
    public ResponseMap getRail(String imei) {
        Device device = this.findById(imei);
        if (device == null) {
            log.error("Device is null. _id={}", imei);
            return ResponseMap.fail(ResponseEnum.STATUS2001.getCode(), ResponseEnum.STATUS2001.getMsg(), imei);
        }
        ResponseMap data = ResponseMap.success();
        List<Map<String, Object>> list = new ArrayList<>();
        if (CollectionUtil.isNotEmpty(device.getRailMap())) {
            for (Map.Entry<String, Map<String, Object>> entry : device.getRailMap().entrySet()) {
                Map<String, Object> temp = new HashMap<>();
                temp.put("id", entry.getKey());
                temp.put("name", entry.getValue().get("name"));
                temp.put("lon", entry.getValue().get("lon"));
                temp.put("lat", entry.getValue().get("lat"));
                temp.put("radius", entry.getValue().get("radius"));
                temp.put("address", entry.getValue().get("address"));

                if (entry.getValue().containsKey("starttime")) {
                    temp.put("starttime", entry.getValue().get("starttime"));
                    temp.put("endedtime", entry.getValue().get("endedtime"));
                    temp.put("week", entry.getValue().get("week"));
                    temp.put("status", entry.getValue().get("status"));

                }else{
                    temp.put("starttime", "00:00");
                    temp.put("endedtime", "23:59");
                    temp.put("week", "1111111");
                    temp.put("status", 1);
                }
                if (entry.getValue().containsKey("updateTime")) {
                    temp.put("updateTime", entry.getValue().get("updateTime"));
                }else{
                    temp.put("updateTime", entry.getValue().get("t"));
                }

                list.add(temp);
            }
        }
        data.put("rails", list);
        return data;
    }

    /**
     * @param imei
     * @param vo
     * @time: 2020/12/4 17:39
     * @author: Rock
     * @version 1.0
     */
    public ResponseMap addRail(String imei, DeviceAddRailReqVO vo) {
        Device device = findById(imei);
        if (device == null) {
            log.error("Device is null. _id={}", imei);
            return ResponseMap.fail(ResponseEnum.STATUS2001.getCode(), ResponseEnum.STATUS2001.getMsg(), imei);
        }
        if (device.getRailMap() == null) {
            device.setRailMap(new HashMap<>());
        }
        Map<String, Object> temp = new HashMap<>();
        temp.put("t", DateUtil.nowTimestampToLong());
        temp.put("c", vo.getOpenid());
        temp.put("name", vo.getName());
        temp.put("lon", vo.getLon());
        temp.put("lat", vo.getLat());
        temp.put("radius", vo.getRadius());
        temp.put("address", vo.getAddress());
        temp.put("starttime", "00:00");
        temp.put("endedtime", "23:59");
        temp.put("week", "1111111");
        temp.put("status", 1);
        temp.put("updateTime", DateUtil.nowTimestampToLong());

        if (vo.getStarttime() != null) {
            boolean paramerRight = true;
            if(!StringUtils.isNumeric(vo.getStarttime().replace(":",""))){
                paramerRight = false;
            }
            if(!StringUtils.isNumeric(vo.getEndedtime().replace(":",""))){
                paramerRight = false;
            }
            if(!paramerRight){
                return ResponseMap.fail(ResponseEnum.STATUS2001.getCode(), ResponseEnum.STATUS2001.getMsg(), imei);
            }
            temp.put("starttime", vo.getStarttime());
            temp.put("endedtime", vo.getEndedtime());
            temp.put("week", vo.getWeek());
            temp.put("status", vo.getStatus());
        }


        String rid = RandomUtil.getRandomStr(8);
        device.getRailMap().put(rid, temp);
        //更新操作
        this.updateById(imei, new Update().set("r", device.getRailMap()));
        ResponseMap data = ResponseMap.success();
        data.put("id", rid);
        return data;
    }

    /**
     * 删除安全区域
     *
     * @param imei
     * @param vo
     * @time: 2020/12/4 17:50
     * @author: Rock
     * @version 1.0
     */
    public ResponseMap delRail(String imei, IdParamReqVO vo) {
        Device device = this.findById(imei);
        if (device == null) {
            log.error("Device is null. _id={}", imei);
            return ResponseMap.fail(ResponseEnum.STATUS2001.getCode(), ResponseEnum.STATUS2001.getMsg(), imei);
        }
        if (CollectionUtil.removeMapKey(device.getRailMap(), vo.getId())) {
            //更新操作
            this.updateById(imei, new UpdateVO().setMap("r", device.getRailMap()));
        }
        return ResponseMap.success();
    }

    /**
     * 更新安全区域
     *
     * @param imei
     * @param vo
     * @time: 2020/12/4 18:26
     * @author: Rock
     * @version 1.0
     */
    public ResponseMap updateRail(String imei, DeviceUpdateRailReqVO vo) {
        Device device = this.findById(imei);
        if (device == null) {
            log.error("Device is null. _id={}", imei);
            return ResponseMap.fail(ResponseEnum.STATUS2001.getCode(), ResponseEnum.STATUS2001.getMsg(), imei);
        }
        if (CollectionUtil.containsKey(device.getRailMap(), vo.getId())) {
            Map<String, Object> updateRail = device.getRailMap().get(vo.getId());
            boolean addressChange = false;
            if (StringUtil.isNotBlank(vo.getName())) {
                updateRail.put("name", vo.getName());
            }
            if (StringUtil.isNotBlank(vo.getLon())) {
                if(ObjectUtils.isEmpty(updateRail.get("log")) || !vo.getLon().equals(updateRail.get("log"))){
                    addressChange = true;
                }
                updateRail.put("lon", vo.getLon());
            }
            if (StringUtil.isNotBlank(vo.getLat())) {
                if(ObjectUtils.isEmpty(updateRail.get("lat")) || !vo.getLon().equals(updateRail.get("lat"))){
                    addressChange = true;
                }
                updateRail.put("lat", vo.getLat());
            }
            if (StringUtil.isNotBlank(vo.getRadius())) {
                updateRail.put("radius", vo.getRadius());
            }
            if (StringUtil.isNotBlank(vo.getAddress())) {
                updateRail.put("address", vo.getAddress());
            }
            if (StringUtil.isNotBlank(vo.getStarttime())) {
                updateRail.put("starttime", vo.getStarttime());
            }
            if (StringUtil.isNotBlank(vo.getEndedtime())) {
                updateRail.put("endedtime", vo.getEndedtime());
            }
            if (StringUtil.isNotBlank(vo.getWeek())) {
                updateRail.put("week", vo.getWeek());
            }
            if (StringUtil.isNotBlank(vo.getStatus())) {
                updateRail.put("status", vo.getStatus());
            }
            //换了新地址应将之前的行为状态删除
            if(addressChange && ObjectUtils.isNotEmpty(updateRail.get("action"))){
                updateRail.put("action","");
            }
            updateRail.put("updateTime", DateUtil.nowTimestampToLong());
            //更新操作
            this.updateById(imei, new Update().set("r", device.getRailMap()));
        }
        return ResponseMap.success();
    }

    /**
     * 获取聊天群组
     *
     * @param imei
     * @time: 2020/12/4 19:00
     * @author: Rock
     * @version 1.0
     */
    public ResponseMap getRelatedChatGroup(String imei) {
        Device device = this.findById(imei);
        if (device == null) {
            log.error("Device is null. _id={}", imei);
            return ResponseMap.fail(ResponseEnum.STATUS2001.getCode(), ResponseEnum.STATUS2001.getMsg(), imei);
        }
        List<Map<String, Object>> list = new ArrayList<>();
        if (CollectionUtil.isNotEmpty(device.getChatGroupMap())) {
            List<ChatGroup> chatGroupList = chatGroupService.listByIds(CollectionUtil.stringToObjectId(device.getChatGroupMap().keySet()));
            for (ChatGroup chatGroup : chatGroupList) {
                Map<String, Object> temp = new HashMap<>();
                temp.put("groupid", chatGroup.getId());
                temp.put("name", "");
                list.add(temp);
            }
        }
        ResponseMap data = ResponseMap.success();
        data.put("chatGroups", list);
        return data;
    }

    /**
     * 添加聊天群组
     *
     * @param imei
     * @param vo
     * @time: 2020/12/7 9:45
     * @author: Rock
     * @version 1.0
     */
    public ResponseMap addRelatedChatGroup(String imei, DeviceAddRelatedChatGroupReqVO vo) {
        Device device = this.findById(imei);
        if (device == null) {
            log.error("Device is null. _id={}", imei);
            return ResponseMap.fail(ResponseEnum.STATUS2001.getCode(), ResponseEnum.STATUS2001.getMsg(), imei);
        }
        if (!ObjectId.isValid(vo.getGroupid())) {
            log.error("param groupid is not ObjectId. groupid={}", vo.getGroupid());
            return ResponseMap.fail(ResponseEnum.STATUS400.getMsg());
        }
        ObjectId chatGroupObjectId = new ObjectId(vo.getGroupid());
        ChatGroup chatGroup = chatGroupService.findById(chatGroupObjectId);
        if (chatGroup == null) {
            log.error("ChatGroup is null. _id={}", vo.getGroupid());
            return ResponseMap.fail();
        }
        if (!CollectionUtil.containsKey(device.getUserMap(), vo.getOpenid())) {
            return ResponseMap.fail(ResponseEnum.STATUS4004.getCode(), "您已解绑成功，请退出app重新进入查看");
        }
        if (CollectionUtil.containsKey(device.getChatGroupMap(), vo.getGroupid())) {
            return ResponseMap.fail(ResponseEnum.STATUS4001.getCode(), imei + " 已在该群组中");
        }
        //更新device表
        addChatGroup(device, vo.getOpenid());
        //更新ChatGroup表
        chatGroupService.addDevice(chatGroup, device);
        return ResponseMap.success();
    }

    /**
     * 退出聊天群组
     *
     * @param imei
     * @param vo
     * @time: 2020/12/15 10:16
     * @author: Rock
     * @version 1.0
     */
    public ResponseMap delRelatedChatGroup(String imei, GroupidParamReqVO vo) {
        Device device = this.findById(imei);
        if (device == null) {
            log.error("Device is null. _id={}", imei);
            return ResponseMap.fail(ResponseEnum.STATUS2001.getCode(), ResponseEnum.STATUS2001.getMsg(), imei);
        }
        if (!ObjectId.isValid(vo.getGroupid())) {
            log.error("param groupid is not ObjectId. groupid={}", vo.getGroupid());
            return ResponseMap.fail();
        }
        ObjectId chatGroupObjectId = new ObjectId(vo.getGroupid());
        ChatGroup chatGroup = chatGroupService.findById(chatGroupObjectId);
        if (chatGroup == null) {
            log.error("ChatGroup is null. _id={}", vo.getGroupid());
            return ResponseMap.fail();
        }
        if (!CollectionUtil.containsKey(device.getUserMap(), vo.getOpenid())) {
            return ResponseMap.fail(ResponseEnum.STATUS4004.getCode(), "您已解绑成功，请退出app重新进入查看");
        }
        if (!CollectionUtil.containsKey(chatGroup.getDeviceMap(), imei)) {
            return ResponseMap.fail(ResponseEnum.STATUS4002.getCode(), imei + " 不在该群组中");
        }
        UpdateVO updateDevice = new UpdateVO();
        UpdateVO updateChatGroup = new UpdateVO();
        if (CollectionUtil.removeMapKey(device.getChatGroupMap(), vo.getGroupid())) {
            updateDevice.setMap("g", device.getChatGroupMap());
            this.updateById(imei, updateDevice);
        }
        if (CollectionUtil.removeMapKey(chatGroup.getDeviceMap(), imei)) {
            updateChatGroup.setMap("d", chatGroup.getDeviceMap());
            chatGroupService.updateById(chatGroupObjectId, updateChatGroup);
        }
        return ResponseMap.success();
    }

    /**
     * 获取设备导航的设置
     *
     * @param vo
     * @time: 2020/12/18 11:33
     * @author: Rock
     * @version 1.0
     */
    public ResponseMap listNavigation(ImeiParamReqVO vo) {
        Device device = this.findById(vo.getImei());
        if (device == null) {
            log.error("Device is null. _id={}", vo.getImei());
            return ResponseMap.fail(ResponseEnum.STATUS2001.getCode(), ResponseEnum.STATUS2001.getMsg(), vo.getImei());
        }
        ResponseMap res = ResponseMap.success();
        res.put("navigationlist", navigationListHandle(device));
        return res;
    }

    /**
     * @param device
     * @time: 2021/1/13 14:13
     * @author: Rock
     * @version 1.0
     */
    private List<Object> navigationListHandle(Device device) {
        List<Object> data = new ArrayList<>();
        if (CollectionUtil.isNotEmpty(device.getNavigationMap())) {
            for (Map.Entry<String, Map<String, Object>> entry : device.getNavigationMap().entrySet()) {
                entry.getValue().remove("t");
                entry.getValue().remove("c");
                entry.getValue().put("id", entry.getKey());
                data.add(entry.getValue());
            }
        }
        return data;
    }

    /**
     * 添加设备导航的设置
     *
     * @param vo
     * @time: 2020/12/18 11:53
     * @author: Rock
     * @version 1.0
     */
    public ResponseMap addNavigation(AddNavigationReqVO vo) {
        Device device = this.findById(vo.getImei());
        if (device == null) {
            log.error("Device is null. _id={}", vo.getImei());
            return ResponseMap.fail(ResponseEnum.STATUS2001.getCode(), ResponseEnum.STATUS2001.getMsg(), vo.getImei());
        }
        if (device.getNavigationMap() == null) {
            device.setNavigationMap(new HashMap<>());
        }
        if (device.getNavigationMap().size() >= 5) {
            return ResponseMap.fail(ResponseEnum.STATUS403.getCode(), "导航地址数量不能超过5个");
        }
        Map<String, Object> map = new HashMap<>();
        map.put("t", DateUtil.nowTimestampToDouble());
        map.put("c", vo.getOpenid());
        map.put("name", vo.getName());
        map.put("address", vo.getAddress());
        map.put("lon", vo.getLon());
        map.put("lat", vo.getLat());
        String id = RandomUtil.getRandomStr(8);
        device.getNavigationMap().put(id, map);
        UpdateVO update = new UpdateVO();
        update.setMap("navigation", device.getNavigationMap());
        this.updateById(vo.getImei(), update);
        //发送kafka
        JSONObject json = new JSONObject();
        json.put("navigationlist", navigationListHandle(device));
        kafkaService.emitDeviceDemand(vo.getImei(), ConstKafka.DEVICE_TYPE_84, json, null);
        ResponseMap res = ResponseMap.success();
        res.put("id", id);
        return ResponseMap.success();
    }

    /**
     * 修改设备导航的设置
     *
     * @param vo
     * @time: 2020/12/18 11:59
     * @author: Rock
     * @version 1.0
     */
    public ResponseMap updateNavigation(UpdateNavigationReqVO vo) {
        Device device = this.findById(vo.getImei());
        if (device == null) {
            log.error("Device is null. _id={}", vo.getImei());
            return ResponseMap.fail(ResponseEnum.STATUS2001.getCode(), ResponseEnum.STATUS2001.getMsg(), vo.getImei());
        }
        if (!CollectionUtil.containsKey(device.getNavigationMap(), vo.getId())) {
            return ResponseMap.fail();
        }
        Map<String, Object> navigation = device.getNavigationMap().get(vo.getId());
        if (StringUtil.isNotBlank(vo.getOpenid())) {
            navigation.put("c", vo.getOpenid());
        }
        if (StringUtil.isNotBlank(vo.getName())) {
            navigation.put("name", vo.getName());
        }
        if (StringUtil.isNotBlank(vo.getAddress())) {
            navigation.put("address", vo.getAddress());
        }
        if (StringUtil.isNotBlank(vo.getLon())) {
            navigation.put("lon", vo.getLon());
        }
        if (StringUtil.isNotBlank(vo.getLat())) {
            navigation.put("lat", vo.getLat());
        }
        UpdateVO update = new UpdateVO();
        update.setMap("navigation", device.getNavigationMap());
        this.updateById(vo.getImei(), update);
        //发送kafka
        JSONObject json = new JSONObject();
        json.put("navigationlist", navigationListHandle(device));
        kafkaService.emitDeviceDemand(vo.getImei(), ConstKafka.DEVICE_TYPE_84, json, null);
        return ResponseMap.success();
    }

    /**
     * 删除设备导航的设置
     *
     * @param vo
     * @time: 2020/12/18 12:09
     * @author: Rock
     * @version 1.0
     */
    public ResponseMap delNavigation(ImeiAndIdsParamReqVO vo) {
        Device device = this.findById(vo.getImei());
        if (device == null) {
            log.error("Device is null. _id={}", vo.getImei());
            return ResponseMap.fail(ResponseEnum.STATUS2001.getCode(), ResponseEnum.STATUS2001.getMsg(), vo.getImei());
        }
        if (!CollectionUtil.isNotEmpty(device.getNavigationMap())) {
            return ResponseMap.fail();
        }
        JSONArray idArr = JSON.parseArray(vo.getIds());
        for (int i = 0; i < idArr.size(); i++) {
            device.getNavigationMap().remove(idArr.getString(i));
        }
        UpdateVO update = new UpdateVO();
        update.setMap("navigation", device.getNavigationMap());
        this.updateById(vo.getImei(), update);
        //发送kafka
        JSONObject json = new JSONObject();
        json.put("navigationlist", navigationListHandle(device));
        kafkaService.emitDeviceDemand(vo.getImei(), ConstKafka.DEVICE_TYPE_84, json, null);
        return ResponseMap.success();
    }

    /**
     * 是否在免打扰的时间内
     *
     * @param imei
     * @param vo
     * @time: 2020/12/18 15:16
     * @author: Rock
     * @version 1.0
     */
    public ResponseMap disturbBanCheck(String imei, BaseAccountReqVO vo) {
        Device device = this.findById(imei);
        if (device == null) {
            log.error("Device is null. _id={}", imei);
            return ResponseMap.fail(ResponseEnum.STATUS2001.getCode(), ResponseEnum.STATUS2001.getMsg(), imei);
        }
        if (CollectionUtil.isNotEmpty(device.getDisBanMap())) {
            int day = DateUtil.getWeekOfDate(new Date());
            for (Map.Entry<String, Map<String, Object>> entry : device.getDisBanMap().entrySet()) {
                Object week = entry.getValue().get("week");
                if (Const.INT_1.equals(entry.getValue().get("status")) && StringUtil.isNotBlank(week)
                        && week.toString().length() > day - 1 && "1".equals(String.valueOf(week.toString().charAt(day - 1)))) {
                    if (StringUtil.isNotBlank(entry.getValue().get("starttime")) && StringUtil.isNotBlank(entry.getValue().get("endedtime"))) {
                        int starttime = Integer.parseInt(entry.getValue().get("starttime").toString().replace(":", ""));
                        int endedtime = Integer.parseInt(entry.getValue().get("endedtime").toString().replace(":", ""));
                        if (DateUtil.getHourAndMinute() >= starttime && DateUtil.getHourAndMinute() <= endedtime) {
                            String name = getDeviceName(device);
                            return ResponseMap.fail(ResponseEnum.STATUS6000.getCode(), name + ResponseEnum.STATUS6000.getMsg());
                        }
                    }
                }
            }
        }
        return ResponseMap.success();
    }

    /**
     * 获取视频通话续费套餐
     *
     * @param imei
     * @param vo
     * @time: 2021/1/6 11:54
     * @author: Rock
     * @version 1.0
     */
    public ResponseMap getVideoRenew(String imei, BaseAccountReqVO vo) {
        Device device = this.findById(imei);
        if (device == null) {
            log.error("Device is null. _id={}", imei);
            return ResponseMap.fail(ResponseEnum.STATUS2001.getCode(), ResponseEnum.STATUS2001.getMsg(), imei);
        }
        ResponseMap res = ResponseMap.success();
        if (device.getVideoEndtime() == null) {
            Update update = new Update();
            update.set("video_endtime", ConstVideo.DEFAULT_VIDEO_TIME);
            this.updateById(imei, update);
            device.setVideoEndtime(ConstVideo.DEFAULT_VIDEO_TIME);
        }
        res.put("video_endtime", String.format("剩余%s分钟", device.getVideoEndtime()));
        res.put("video_permanent", device.getVideoPermanent() == null ? 1 : device.getVideoPermanent());

        List<Object> paymentMode = new ArrayList<>();
        Map<String, Object> temp = new HashMap<>();
        temp.put("type", "alipay");
        temp.put("name", "支付宝支付");
        temp.put("image", baseBucketTool.getDOMAIN() + BaseBucketTool.ACCOUNT_COMMON_PATH + "alipay.png");
        paymentMode.add(temp);
        temp = new HashMap<>();
        temp.put("type", "wechat");
        temp.put("name", "微信支付");
        temp.put("image", baseBucketTool.getDOMAIN() + BaseBucketTool.ACCOUNT_COMMON_PATH + "wechat.png");
        paymentMode.add(temp);
        res.put("payment_mode", paymentMode);

        List<Map<String, Object>> renewalPlan = new ArrayList<>();
        if (StringUtil.isNotBlank(device.getModules())) {
            if (device.getModules().contains(ConstVideo.V0SW)) {
                //声网
                for (Map<String, Object> map : commonProperties.getRenew()) {
                    Map<String, Object> tempMap = new HashMap<>();
                    tempMap.put("id", Integer.parseInt(map.get("id").toString()));
                    tempMap.put("price", map.get("price"));
                    tempMap.put("name", map.get("minute") + "分钟");
                    renewalPlan.add(tempMap);
                }
            } else if (device.getModules().contains(ConstVideo.V0JF)) {
                //Juphoon
                for (Map<String, Object> map : commonProperties.getJuphoon()) {
                    Map<String, Object> tempMap = new HashMap<>();
                    tempMap.put("id", Integer.parseInt(map.get("id").toString()));
                    tempMap.put("price", map.get("price"));
                    //tempMap.put("name", "map.get("name")");
                    tempMap.put("name", "永久开通");
                    renewalPlan.add(tempMap);
                }
            }
        }
        res.put("renewal_plan", renewalPlan);
        return res;
    }

    /**
     * 查询语音提醒列表
     *
     * @param imei
     * @time: 2021/2/4 16:11
     * @author: Rock
     * @version 1.0
     */
    public ResponseMap getVoiceAlarm(String imei) {
        Device device = this.findById(imei);
        if (device == null) {
            log.error("Device is null. _id={}", imei);
            return ResponseMap.fail(ResponseEnum.STATUS2001.getCode(), ResponseEnum.STATUS2001.getMsg(), imei);
        }
        ResponseMap res = ResponseMap.success();
        List<Object> data = new ArrayList<>();
        if (CollectionUtil.isNotEmpty(device.getVoiceAlarm())) {
            boolean isUpdate = false;
            for (Map.Entry<String, Map<String, Object>> entry : device.getVoiceAlarm().entrySet()) {
                if (entry.getValue().get("alarm_time") instanceof Date) {
                    //处理voiceAlarm的Date
                    DateUtil.hanldeMongoDate((Date) entry.getValue().get("alarm_time"), 2);
                }
                Map<String, Object> temp = new HashMap<>();
                temp.put("id", entry.getKey());
                temp.put("duration", entry.getValue().get("duration"));
                temp.put("week", entry.getValue().get("week"));
                temp.put("text", entry.getValue().get("text"));
                temp.put("time", entry.getValue().get("time"));
                if (StringUtil.isNotBlank(entry.getValue().get("content"))) {
                    temp.put("voiceURL", baseBucketTool.getDOMAIN() + BaseBucketTool.VOICEALARM_COMMON_PATH + entry.getValue().get("content"));
                }
                if (StringUtil.isNumeric(entry.getValue().get("status"))) {
                    Integer status = Integer.parseInt(entry.getValue().get("status").toString());
                    //打开的, 且是一次性的
                    if (Const.INT_1.equals(status) && "0000000".equals(entry.getValue().get("week"))){
                        // 且闹钟时间已经超过现在时间了,且 修改的时间(t) 在闹钟响的时间 之前的. 需要改改变状态
                        Double t = Double.valueOf(entry.getValue().get("t").toString());
                        Date updateDate = new Date(t.longValue() * 1000);
                        Object alarm_timeDate = entry.getValue().get("alarm_time");
                        if(alarm_timeDate instanceof Date
                                && new Date().compareTo((Date)alarm_timeDate) == 1
                                && updateDate.compareTo((Date)alarm_timeDate) == -1){
                            status = 0;
                            entry.getValue().put("status", status);
                            isUpdate = true;
                        }
                    }
                    temp.put("status", status);
                }
                data.add(0, temp);
            }
            if (isUpdate) {
                Update updateDevice = new Update();
                updateDevice.set("va", device.getVoiceAlarm());
                this.updateById(device.getId(), updateDevice);
            }
        }
        //智能闹钟开关状态（0：关，1：开）
        res.put("smartAlarmStatus",ObjectUtils.isEmpty(device.getSmartAlarmStatus())?1:device.getSmartAlarmStatus());
        res.put("voiceAlarms", data);
        return res;
    }

    /**
     * @param imei
     * @param vo
     * @param content
     * @time: 2021/2/3 10:25
     * @author: Rock
     * @version 1.0
     */
    public ResponseMap addVoiceAlarm(String imei, AddVoiceAlarmReqVO vo, MultipartFile content) throws IOException {
        Device device = this.findById(imei);
        if (device == null) {
            log.error("Device is null. _id={}", imei);
            return ResponseMap.fail(ResponseEnum.STATUS2001.getCode(), ResponseEnum.STATUS2001.getMsg(), imei);
        }
        if (device.getVoiceAlarm() == null) {
            device.setVoiceAlarm(new HashMap<>());
        }
        if (device.getVoiceAlarm().size() >= 3) {
            return ResponseMap.fail("闹钟数量不能超过3个");
        }
        for (Map.Entry<String, Map<String, Object>> entry : device.getVoiceAlarm().entrySet()) {
            if (entry.getValue().get("alarm_time") instanceof Date) {
                //处理voiceAlarm的Date
                DateUtil.hanldeMongoDate((Date) entry.getValue().get("alarm_time"), 2);
            }
        }
        ResponseMap res = ResponseMap.success();
        Map<String, Object> temp = new HashMap<>();
        boolean flag = false;
        if (content != null && !content.isEmpty()) {
            //生成文件名并上传
            String fileName = BaseBucketTool.createFileNameToAmr();
            baseBucketTool.upload(BaseBucketTool.VOICEALARM_COMMON_PATH + fileName, content, 2);
            temp.put("content", fileName);
            temp.put("size", content.getSize());
            temp.put("duration", vo.getDuration());
            flag = true;
        } else {
            temp.put("content", "");
            temp.put("size", 0);
            temp.put("duration", 0d);
        }
        int timeInt = 0;
        int hour = 0;
        int minute = 0;
        if (StringUtil.isNumeric(vo.getTime().replace(":", ""))) {
            timeInt = Integer.parseInt(vo.getTime().replace(":", ""));
            String[] tempArr = vo.getTime().split(":");
            if (tempArr.length > 1) {
                hour = Integer.parseInt(tempArr[0]);
                minute = Integer.parseInt(tempArr[1]);
            }
        }
        if ("0000000".equals(vo.getWeek())) {
            Date alarmTime = new Date();
            if (DateUtil.getHourAndMinute() >= timeInt) {
                alarmTime = DateUtil.addDay(new Date(), 1);
            }
            alarmTime = DateUtil.setHourAndMinute(alarmTime, hour, minute);
            temp.put("alarm_time", alarmTime);
        }
        temp.put("week", vo.getWeek());
        temp.put("text", vo.getText());
        temp.put("time", vo.getTime());
        temp.put("status", vo.getStatus());
        temp.put("t", DateUtil.nowTimestampToLong());
        String idKey = RandomUtil.getRandomStr(8);
        device.getVoiceAlarm().put(idKey, temp);
        this.updateById(device.getId(), new Update().set("va", device.getVoiceAlarm()));
        //设备端同步
        syncVoiceAlarm(device.getId(), device.getVoiceAlarm(), vo.getOpenid());
        if (flag) {
            res.put("voiceURL", baseBucketTool.getDOMAIN() + BaseBucketTool.VOICEALARM_COMMON_PATH + temp.get("content"));
        }
        res.put("id", idKey);
        return res;
    }


    /**
     * @description 设置智能闹钟开关
     * @author cwj
     * @param [imei, smartAlarmStatusVo]
     * @return com.iot08.common.utils.response.ResponseMap
     * @date @time 2025/5/19 17:44
     **/
    public ResponseMap smartAlarmStatusSetting(String imei, SmartAlarmStatusVo vo){
        Device device = this.findById(imei);
        if (device == null) {
            log.error("Device is null. _id={}", imei);
            return ResponseMap.fail(ResponseEnum.STATUS2001.getCode(), ResponseEnum.STATUS2001.getMsg(), imei);
        }
        //检查设备是否在线，不在线不能下发
        String onlineStatus = redisClusterService.hget(imei, ConstCacheField.ONLINE_STATUS);
        if (!"1".equals(onlineStatus)) {
            return ResponseMap.fail(ResponseEnum.STATUS5001.getCode(), ResponseEnum.STATUS5001.getMsg());
        }
        //更新智能闹钟开关状态
        Update update = new Update();
        update.set("smartAlarmStatus",vo.getSmartAlarmStatus());
        this.updateById(imei,update);
        JSONObject kafkaJson = new JSONObject();
        kafkaJson.put("smartAlarmStatus", vo.getSmartAlarmStatus());
        kafkaService.emitDeviceDemand(imei, ConstKafka.SMART_ALARM_STATUS, kafkaJson, vo.getOpenid());
        return ResponseMap.success();
    }

    /**
     * @param imei
     * @param voiceAlarm
     * @time: 2021/2/3 9:55
     * @author: Rock
     * @version 1.0
     */
    private void syncVoiceAlarm(String imei, Map<String, Map<String, Object>> voiceAlarm, String openid) {
        if (voiceAlarm == null) {
            voiceAlarm = new HashMap<>();
        }
        List<Object> alarms = new ArrayList<>();
        for (Map.Entry<String, Map<String, Object>> entry : voiceAlarm.entrySet()) {
            if (StringUtil.isNumeric(entry.getValue().get("status"))) {
                Map<String, Object> temp = new HashMap<>();
                temp.put("start", entry.getValue().get("time"));
                temp.put("week", entry.getValue().get("week"));
                temp.put("text", entry.getValue().get("text"));
//                temp.put("duration", entry.getValue().get("duration"));
//                temp.put("size", entry.getValue().get("size"));
                temp.put("status", Integer.valueOf(entry.getValue().get("status").toString()));
                if (StringUtil.isNotBlank(entry.getValue().get("content"))) {
                    temp.put("url", baseBucketTool.getDOMAIN() + BaseBucketTool.VOICEALARM_COMMON_PATH + entry.getValue().get("content"));
                }
                alarms.add(0, temp);
            }
        }
        JSONObject data = new JSONObject();
        data.put("alarm", alarms);
        kafkaService.emitDeviceDemand(imei, ConstKafka.DEVICE_TYPE_Alarm, data, openid);
    }

    /**
     * @param imei
     * @param vo
     * @param content
     * @time: 2021/2/3 10:52
     * @author: Rock
     * @version 1.0
     */
    public ResponseMap updateVoiceAlarm(String imei, UpdateVoiceAlarmReqVO vo,
                                        MultipartFile content) throws IOException {
        Device device = this.findById(imei);
        if (device == null) {
            log.error("Device is null. _id={}", imei);
            return ResponseMap.fail(ResponseEnum.STATUS2001.getCode(), ResponseEnum.STATUS2001.getMsg(), imei);
        }
        if (!CollectionUtil.containsKey(device.getVoiceAlarm(), vo.getId())) {
            log.error("voice alarm is not found, imei={}. vid={}", imei, vo.getId());
            return ResponseMap.fail(ResponseEnum.STATUS4007.getCode(), "语音提醒未找到");
        }
        for (Map.Entry<String, Map<String, Object>> entry : device.getVoiceAlarm().entrySet()) {
            if (entry.getValue().get("alarm_time") instanceof Date) {
                //处理voiceAlarm的Date
                DateUtil.hanldeMongoDate((Date) entry.getValue().get("alarm_time"), 2);
            }
        }
        Map<String, Object> voiceAlarm = device.getVoiceAlarm().get(vo.getId());
        ResponseMap res = ResponseMap.success();
        if (content != null && !content.isEmpty()) {
            if (StringUtil.isNotBlank(voiceAlarm.get("content"))) {
                //删除旧文件
                baseBucketTool.delFile(BaseBucketTool.VOICEALARM_COMMON_PATH + voiceAlarm.get("content"));
            }
            //生成文件名并上传
            String fileName = BaseBucketTool.createFileNameToAmr();
            baseBucketTool.upload(BaseBucketTool.VOICEALARM_COMMON_PATH + fileName, content, 2);
            res.put("voiceURL", baseBucketTool.getDOMAIN() + BaseBucketTool.VOICEALARM_COMMON_PATH + fileName);
            voiceAlarm.put("content", fileName);
            voiceAlarm.put("duration", vo.getDuration());
        }
        int timeInt = 0;
        int hour = 0;
        int minute = 0;
        if (StringUtil.isNotBlank(vo.getTime()) && StringUtil.isNumeric(vo.getTime().replace(":", ""))) {
            timeInt = Integer.parseInt(vo.getTime().replace(":", ""));
            String[] tempArr = vo.getTime().split(":");
            if (tempArr.length > 1) {
                hour = Integer.parseInt(tempArr[0]);
                minute = Integer.parseInt(tempArr[1]);
            }
        }
        if (StringUtil.isNotBlank(vo.getWeek())) {
            voiceAlarm.put("week", vo.getWeek());
            if ("0000000".equals(vo.getWeek())) {
                Date alarmTime = new Date();
                if (DateUtil.getHourAndMinute() >= timeInt) {
                    alarmTime = DateUtil.addDay(new Date(), 1);
                }
                alarmTime = DateUtil.setHourAndMinute(alarmTime, hour, minute);
                voiceAlarm.put("alarm_time", alarmTime);
            }
        }
        if (StringUtil.isNotBlank(vo.getText())) {
            voiceAlarm.put("text", vo.getText());
        }
        if (StringUtil.isNotBlank(vo.getTime())) {
            voiceAlarm.put("time", vo.getTime());
        }
        if (StringUtil.isNotBlank(vo.getStatus())) {
            voiceAlarm.put("status", vo.getStatus());
        }
        //修改更新改时间
        voiceAlarm.put("t", DateUtil.nowTimestampToLong());
        device.getVoiceAlarm().put(vo.getId(), voiceAlarm);
        Update updateDevice = new Update();
        updateDevice.set("va", device.getVoiceAlarm());
        this.updateById(device.getId(), updateDevice);
        syncVoiceAlarm(device.getId(), device.getVoiceAlarm(), vo.getOpenid());
        return res;
    }

    /**
     * 删除语音提醒
     *
     * @param imei
     * @param vo
     * @time: 2021/2/3 11:03
     * @author: Rock
     * @version 1.0
     */
    public ResponseMap delVoiceAlarm(String imei, IdParamReqVO vo) {
        Device device = this.findById(imei);
        if (device == null) {
            log.error("Device is null. _id={}", imei);
            return ResponseMap.fail(ResponseEnum.STATUS2001.getCode(), ResponseEnum.STATUS2001.getMsg(), imei);
        }
        //禁止删除闹钟
        return ResponseMap.fail(ResponseEnum.STATUS400.getCode(), "禁止删除闹钟");

//        Map<String, Object> delData = CollectionUtil.removeMapKeyData(device.getVoiceAlarm(), vo.getId());
//        if (delData != null) {
//            for (Map.Entry<String, Map<String, Object>> entry : device.getVoiceAlarm().entrySet()) {
//                if (entry.getValue().get("alarm_time") instanceof Date) {
//                    //处理voiceAlarm的Date
//                    DateUtil.hanldeMongoDate((Date) entry.getValue().get("alarm_time"), 2);
//                }
//            }
//            this.updateById(device.getId(), new UpdateVO().setMap("va", device.getVoiceAlarm()));
//            syncVoiceAlarm(device.getId(), device.getVoiceAlarm(), vo.getOpenid());
//            //删除文件
//            if (StringUtil.isNotBlank(delData.get("content"))) {
//                //删除旧文件
//                baseBucketTool.delFile(BaseBucketTool.VOICEALARM_COMMON_PATH + delData.get("content"));
//            }
//        }
//        return ResponseMap.success();
    }

    /**
     * 查询免打扰设置列表
     *
     * @param imei
     * @time: 2021/2/3 11:19
     * @author: Rock
     * @version 1.0
     */
    public ResponseMap getDisturbBan(String imei) {
        Device device = this.findById(imei);
        if (device == null) {
            log.error("Device is null. _id={}", imei);
            return ResponseMap.fail(ResponseEnum.STATUS2001.getCode(), ResponseEnum.STATUS2001.getMsg(), imei);
        }
        ResponseMap res = ResponseMap.success();
        List<Object> disturbBans = new ArrayList<>();
        if (CollectionUtil.isNotEmpty(device.getDisBanMap())) {
            for (Map.Entry<String, Map<String, Object>> entry : device.getDisBanMap().entrySet()) {
                Map<String, Object> temp = new HashMap<>();
                temp.put("id", entry.getKey());
                temp.put("week", entry.getValue().get("week"));
                temp.put("starttime", entry.getValue().get("starttime"));
                temp.put("endedtime", entry.getValue().get("endedtime"));
                temp.put("status", entry.getValue().get("status"));
                disturbBans.add(0, temp);
            }
        }
        res.put("smartDisturbBanStatus",ObjectUtils.isEmpty(device.getSmartDisturbBanStatus())?1:device.getSmartDisturbBanStatus());
        res.put("disturbBans", disturbBans);
        return res;
    }

    /**
     * 添加免打扰设置（上课禁用）
     *
     * @param imei
     * @param vo
     * @time: 2021/2/3 11:46
     * @author: Rock
     * @version 1.0
     */
    public ResponseMap addDisturbBan(String imei, AddDisturbBanReqVO vo) {
        Device device = this.findById(imei);
        if (device == null) {
            log.error("Device is null. _id={}", imei);
            return ResponseMap.fail(ResponseEnum.STATUS2001.getCode(), ResponseEnum.STATUS2001.getMsg(), imei);
        }
        if (device.getDisBanMap() == null) {
            device.setDisBanMap(new HashMap<>());
        }
        if (device.getDisBanMap().size() >= 4) {
            return ResponseMap.fail("上课禁用数量不能超过4个");
        }
        Map<String, Object> temp = new HashMap<>();
        temp.put("week", vo.getWeek());
        temp.put("starttime", vo.getStarttime());
        temp.put("endedtime", vo.getEndedtime());
        temp.put("status", vo.getStatus());
        temp.put("accesstoken", vo.getAccesstoken());
        temp.put("openid", vo.getOpenid());
        temp.put("t", DateUtil.nowTimestampToDouble());
        String idKey = RandomUtil.getRandomStr(8);
        device.getDisBanMap().put(idKey, temp);
        Update updateDevice = new Update();
        updateDevice.set("disBan", device.getDisBanMap());
        this.updateById(device.getId(), updateDevice);
        syncDisturbBan(device.getId(), device.getDisBanMap(), vo.getOpenid());
        ResponseMap res = ResponseMap.success();
        res.put("id", idKey);
        return res;
    }

    /**
     * @param imei
     * @param disturbBan
     * @time: 2021/2/3 11:44
     * @author: Rock
     * @version 1.0
     */
    private void syncDisturbBan(String imei, Map<String, Map<String, Object>> disturbBan, String openid) {
        if (disturbBan == null) {
            disturbBan = new HashMap<>();
        }
        List<Object> disturb = new ArrayList<>();
        for (Map.Entry<String, Map<String, Object>> entry : disturbBan.entrySet()) {
            if (StringUtil.isNumeric(entry.getValue().get("status")) ) {
                Map<String, Object> temp = new HashMap<>();
                temp.put("start", entry.getValue().get("starttime"));
                temp.put("end", entry.getValue().get("endedtime"));
                temp.put("week", entry.getValue().get("week"));
                temp.put("status", Integer.valueOf(entry.getValue().get("status").toString()));
                disturb.add(0, temp);
            }
        }
        JSONObject data = new JSONObject();
        data.put("disturb", disturb);
        data.put("status", 1);
        kafkaService.emitDeviceDemand(imei, ConstKafka.DEVICE_TYPE_Disturb, data, openid);
    }


    /**
     * @description 智能上课禁用开关设置
     * @author cwj
     * @param [imei, vo]
     * @return com.iot08.common.utils.response.ResponseMap
     * @date @time 2025/5/20 11:21
     **/
    public ResponseMap smartDisturbBanStatusSetting(String imei, SmartDisturbBanStatusReqVO vo){
        Device device = this.findById(imei);
        if (device == null) {
            log.error("Device is null. _id={}", imei);
            return ResponseMap.fail(ResponseEnum.STATUS2001.getCode(), ResponseEnum.STATUS2001.getMsg(), imei);
        }
        //检查设备是否在线，不在线不能下发
        String onlineStatus = redisClusterService.hget(imei, ConstCacheField.ONLINE_STATUS);
        if (!"1".equals(onlineStatus)) {
            return ResponseMap.fail(ResponseEnum.STATUS5001.getCode(), ResponseEnum.STATUS5001.getMsg());
        }
        //更新智能闹钟开关状态
        Update update = new Update();
        update.set("smartDisturbBanStatus",vo.getSmartDisturbBanStatus());
        this.updateById(imei,update);
        JSONObject kafkaJson = new JSONObject();
        kafkaJson.put("smartDisturbBanStatus", vo.getSmartDisturbBanStatus());
        kafkaService.emitDeviceDemand(imei, ConstKafka.SMART_DISTURB_STATUS, kafkaJson, vo.getOpenid());
        return ResponseMap.success();
    }

    /**
     * 修改免打扰设置
     *
     * @param imei
     * @param vo
     * @time: 2021/2/3 11:51
     * @author: Rock
     * @version 1.0
     */
    public ResponseMap updateDisturbBan(String imei, UpdateDisturbBanReqVO vo) {
        Device device = this.findById(imei);
        if (device == null) {
            log.error("Device is null. _id={}", imei);
            return ResponseMap.fail(ResponseEnum.STATUS2001.getCode(), ResponseEnum.STATUS2001.getMsg(), imei);
        }
        if (!CollectionUtil.containsKey(device.getDisBanMap(), vo.getId())) {
            log.error("disturb ban is not found, imei={}. did={}", imei, vo.getId());
            return ResponseMap.fail(ResponseEnum.STATUS4007.getCode(), "免打扰设置未找到");
        }
        Map<String, Object> disBan = device.getDisBanMap().get(vo.getId());
        if (StringUtil.isNotBlank(vo.getWeek())) {
            disBan.put("week", vo.getWeek());
        }
        if (StringUtil.isNotBlank(vo.getStarttime())) {
            disBan.put("starttime", vo.getStarttime());
        }
        if (StringUtil.isNotBlank(vo.getEndedtime())) {
            disBan.put("endedtime", vo.getEndedtime());
        }
        if (StringUtil.isNotBlank(vo.getStatus())) {
            disBan.put("status", vo.getStatus());
        }
        device.getDisBanMap().put(vo.getId(), disBan);
        this.updateById(device.getId(), new Update().set("disBan", device.getDisBanMap()));
        syncDisturbBan(device.getId(), device.getDisBanMap(), vo.getOpenid());
        return ResponseMap.success();
    }

    /**
     * 删除免打扰设置
     *
     * @param imei
     * @time: 2021/2/3 12:06
     * @author: Rock
     * @version 1.0
     */
    public ResponseMap delDisturbBan(String imei, IdParamReqVO vo) {
        Device device = this.findById(imei);
        if (device == null) {
            log.error("Device is null. _id={}", imei);
            return ResponseMap.fail(ResponseEnum.STATUS2001.getCode(), ResponseEnum.STATUS2001.getMsg(), imei);
        }
        Map<String, Object> delData = CollectionUtil.removeMapKeyData(device.getDisBanMap(), vo.getId());
        if (delData != null) {
            this.updateById(device.getId(), new UpdateVO().setMap("disBan", device.getDisBanMap()));
            syncDisturbBan(device.getId(), device.getDisBanMap(), vo.getOpenid());
        }
        return ResponseMap.success();
    }

    /**
     * 获取设备信息
     * @param imei
     * @param vo
     * @time: 2021/2/3 14:50
     * @author: Rock
     * @version 1.0
     */
    public ResponseMap getInfoToJuHuo(String imei, BaseAccountReqVO vo) {
        Device device = this.findById(imei);
        if (device == null) {
            log.error("Device is null. id={}. getInfoToJuHuo", imei);
            return ResponseMap.fail(ResponseEnum.STATUS2001.getCode(), ResponseEnum.STATUS2001.getMsg(), imei);
        }
        ResponseMap res = ResponseMap.success();
        res.put("imei", imei);
        res.put("vendor", StringUtil.isBlank(device.getVendor()) ? 20000 : device.getVendor());
        res.put("name", getDeviceName(device));
        res.put("phone", device.getPhone());
        res.put("avator", baseBucketTool.getDOMAIN() + BaseBucketTool.DEVICE_COMMON_PATH
                + (StringUtil.isBlank(device.getImage()) ? Const.DEFAULT_JPG : device.getImage()));
        res.put("sex", StringUtil.isBlank(device.getSex()) ? "girl" : device.getSex());
        res.put("grade", StringUtil.isBlank(device.getGrade()) ? "" : device.getGrade());
        res.put("birthday", device.getBirthday());
        if (device.getUserMap()!= null && device.getUserMap().containsKey(vo.getOpenid())) {
            //关系
            Object relationship = device.getUserMap().get(vo.getOpenid()).get("relationship");
            if (relationship != null) {
                res.put("relationship", relationship);
            }
            Object relationship_image_id = device.getUserMap().get(vo.getOpenid()).get("relationship_image_id");
            if (relationship_image_id != null) {
                res.put("relationship_image_id", relationship_image_id);
            }
        }

        res.put("opFlower", device.getFlower());
        res.put("opSosSms", device.getSOS_AL());
        res.put("opLowBat", device.getLOWBAT_AL());
        res.put("opDialSwitch", device.getDialSwitch() == null ? 1 : device.getDialSwitch());

        res.put("opSettingVolume", device.getVolume() == null ? Const.DEFAULT_DEVICE_VOLUME : device.getVolume());
        res.put("opRejectStrangeCall", device.getRejectStrange() == null ? 0 : device.getRejectStrange());
        res.put("opLocationMode", device.getLocMode() == null ? Const.DEFAULT_DEVICE_LOCMODE : device.getLocMode());
        if(device.getLocModeMin() != null){
            res.put("opLocationModeMin", device.getLocModeMin());
        }else{
            //学之友词典笔要的定位默认, 此属性不影响其他 赛诺设备
            //没有的话,默认给个120分钟
            res.put("opLocationModeMin", 120);
        }

        if(device.getWatchCustomFunction() != null){
            if(device.getWatchCustomFunction().contains("RSE")){
                //预留省电模式状态 1:打开, 0:关闭 (自动配置有RSE才有)
                res.put("opPowerModel", device.getPowerModelSW());
            }
            if(device.getWatchCustomFunction().contains("ASO")){
                //自动接通状态 1:打开, 0:关闭 (自动配置有ASO才有)
                res.put("asoStatus", device.getAsoStatus());
            }
            if(device.getWatchCustomFunction().contains("SR")){
                //久坐提醒状态 1:打开, 0:关闭 (自动配置有SR才有) (上午/下午有一个打开就是开的)
                res.put("sedentaryStatus", device.getSedentaryStatus());
            }
            if(device.getWatchCustomFunction().contains("CMSG")){
                //代收短信状态 1:打开, 0:关闭 (自动配置有CMSG才有)
                res.put("cmsgStatus", device.getCmsgStatus());
            }
            if(device.getWatchCustomFunction().contains("LOSSDEV")){
                //设备挂失状态 1:打开, 0:关闭 (自动配置有LOSSDEV才有)
                res.put("lossDevStatus", device.getLossDevStatus());
            }
        }

        res.put("battery", device.getBattery() == null ? 0 : device.getBattery());
        int currLevel = device.getCurrLevel() == null ? 0 : device.getCurrLevel();
        if (currLevel > 4){
            currLevel = 4;
        }
        res.put("curr_level", currLevel);
        if (device.getMaxLevel() == null || device.getMaxLevel() < 0) {
            res.put("max_level", 0);
        } else {
            Integer maxLevel = device.getMaxLevel();
            if (maxLevel > 4){
                maxLevel = 4;
            }
            res.put("max_level", maxLevel);
        }
        if (StringUtil.isNotBlank(device.getPlatform())) {
            res.put("platform", device.getPlatform());
        }
        Map<String, Object> tempLoc = new HashMap<>();
        //设备位置信息
        if ((device.getLoc() != null && device.getLoc().size() >= 0) || (device.getNowloc() != null && device.getNowloc().size() > 0)) {
            if (device.getNowloc() == null || device.getNowloc().size() <= 0) {
                tempLoc.put("lon", device.getLoc().get("lon"));
                tempLoc.put("lat", device.getLoc().get("lat"));
                tempLoc.put("useBgAdd", device.getLoc().get("useBgAdd") == null ? 0 : device.getLoc().get("useBgAdd"));
                tempLoc.put("loc_type", device.getLoc().get("T") == null ? "LBS" : device.getLoc().get("T"));
                tempLoc.put("timestamp", device.getLoc().get("t"));
                tempLoc.put("radius", device.getLoc().get("radius") == null ? 0 : device.getLoc().get("radius"));
                tempLoc.put("address", device.getLoc().get("addr") == null ? "" : device.getLoc().get("addr"));
                if (StringUtil.isNotBlank(device.getLoc().get("id"))) {
                    tempLoc.put("id", device.getLoc().get("id").toString());
                }
                res.put("lastLocation", tempLoc);
            } else {
                if (!StringUtil.isNumeric(device.getNowloc().get("timestamp")) || !StringUtil.isNumeric(device.getLoc().get("t"))
                        || Double.parseDouble(device.getLoc().get("t").toString()) > Double.parseDouble(device.getNowloc().get("timestamp").toString())) {
                    tempLoc.put("lon", device.getLoc().get("lon"));
                    tempLoc.put("lat", device.getLoc().get("lat"));
                    tempLoc.put("useBgAdd", device.getLoc().get("useBgAdd") == null ? 0 : device.getLoc().get("useBgAdd"));
                    tempLoc.put("loc_type", device.getLoc().get("T") == null ? "LBS" : device.getLoc().get("T"));
                    tempLoc.put("timestamp", device.getLoc().get("t"));
                    tempLoc.put("radius", device.getLoc().get("radius") == null ? 0 : device.getLoc().get("radius"));
                    tempLoc.put("address", device.getLoc().get("addr") == null ? "" : device.getLoc().get("addr"));
                    if (StringUtil.isNotBlank(device.getLoc().get("id"))) {
                        tempLoc.put("id", device.getLoc().get("id").toString());
                    }
                    res.put("lastLocation", tempLoc);
                } else {
                    tempLoc.put("lon", device.getNowloc().get("lon"));
                    tempLoc.put("lat", device.getNowloc().get("lat"));
                    tempLoc.put("useBgAdd", device.getNowloc().get("useBgAdd") == null ? 0 : device.getNowloc().get("useBgAdd"));
                    tempLoc.put("loc_type", device.getNowloc().get("loctype") == null ? "LBS" : device.getNowloc().get("loctype"));
                    tempLoc.put("timestamp", device.getNowloc().get("timestamp"));
                    tempLoc.put("radius", device.getNowloc().get("radius") == null ? 0 : device.getNowloc().get("radius"));
                    tempLoc.put("address", device.getNowloc().get("addr") == null ? "" : device.getLoc().get("addr"));
                    tempLoc.put("id", device.getNowloc().get("imei") == null ? null : device.getNowloc().get("imei").toString());
                    res.put("lastLocation", tempLoc);
                }
            }
        }
        if (CollectionUtil.isNotEmpty(device.getChatGroupMap())) {
            redisClusterService.hset(imei, ConstCacheField.ACTIVE_STATUS, "1");
        } else {
            redisClusterService.hset(imei, ConstCacheField.ACTIVE_STATUS, "0");
        }
        if (Const.INT_1.equals(device.getIsWatchCustomFunction()) && StringUtil.isNotBlank(device.getWatchCustomFunction())
                && device.getWatchCustomFunction().contains("DEVTYPE:")) {
            String[] tempArr = device.getWatchCustomFunction().split("DEVTYPE:");
            tempArr = tempArr[tempArr.length - 1].split(",");
            if (StringUtil.isNumeric(tempArr[0])) {
                res.put("devOrientGroup", Integer.parseInt(tempArr[0]));
            }
        }
        return res;
    }


    /**
     * @description 查询设备拨号盘状态、陌生人来电拒绝状态
     * @author cwj
     * @param [imei, vo]
     * @return com.iot08.common.utils.response.ResponseMap
     * @date @time 2025/4/25 18:06
     **/
    public ResponseMap getDailSwitch(String imei) {
        Device device = this.findById(imei);
        if (device == null) {
            log.error("Device is null. id={}. getInfoToJuHuo", imei);
            return ResponseMap.fail(ResponseEnum.STATUS2001.getCode(), ResponseEnum.STATUS2001.getMsg(), imei);
        }
        ResponseMap res = ResponseMap.success();
        res.put("imei", imei);
        res.put("opDialSwitch", device.getDialSwitch() == null ? 1 : device.getDialSwitch());
        res.put("opRejectStrangeCall", device.getRejectStrange() == null ? 0 : device.getRejectStrange());
        res.put("opLocationMode", device.getLocMode() == null ? Const.DEFAULT_DEVICE_LOCMODE : device.getLocMode());
        return res;
    }

    /**
     * 获取管理员名称和电话号码
     * @param imei
     * @param vo
     * @time: 4/29/22 10:47 AM
     * @author: Weichao
     * @version 1.0
     */
    public ResponseMap getAdminInfo(String imei, BaseAccountReqVO vo) {
        JSONObject res = new JSONObject();
        Device device = this.findById(imei);
        if (device == null) {
            return ResponseMap.fail(ResponseEnum.STATUS2001.getCode(), ResponseEnum.STATUS2001.getMsg(), imei);
        }
        Map<String, Map<String, Object>> userMap = device.getUserMap();
        for (Map<String, Object> item : userMap.values()) {
            Object identity = item.get("identity");
            if(identity != null){
                String identityStr = identity.toString();
                if ("admin".equals(identityStr)){
                    res.put("admin_name",item.getOrDefault("relationship", ""));
                    res.put("admin_phone",item.getOrDefault("phone", ""));
                    res.put("admin_relationship",item.getOrDefault("relationship", ""));
                    return ResponseMap.success();
                }
//                else if ("visitor".equals(identityStr)) {
//
//                }
            }

        }
        res.put("admin_name","");
        res.put("admin_phone","");
        res.put("admin_relationship","");
        return ResponseMap.success();

    }

    /**
     * 操作设备
     *
     * @param imei
     * @param vo
     * @time: 2021/2/4 10:57
     * @author: Rock
     * @version 1.0
     */
    public ResponseMap operationDevice(String imei, OperationDeviceReqVO vo) {
        Device device = this.findById(imei);
        if (device == null) {
            log.error("Device is null. id={}. operationDevice vo={}", imei, vo);
            return ResponseMap.fail(ResponseEnum.STATUS2001.getCode(), ResponseEnum.STATUS2001.getMsg(), imei);
        }
        String onlineStatus = redisClusterService.hget(imei, ConstCacheField.ONLINE_STATUS);
        if ((StringUtil.isNotBlank(vo.getOpMonitorPhone()) || StringUtil.isNotBlank(vo.getOpPowerOff()) || StringUtil.isNotBlank(vo.getOpPhoto()) || StringUtil.isNotBlank(vo.getOpFind()))
                && !"1".equals(onlineStatus)) {
            return ResponseMap.fail(ResponseEnum.STATUS5001.getCode(), ResponseEnum.STATUS5001.getMsg());
        }
        boolean isUpdate = false;
        Update updateDevice = new Update();
        JSONObject kafkaJson = new JSONObject();
        if (vo.getOpRejectStrangeCall() != null) {
            int temp = 0;
            if (vo.getOpRejectStrangeCall() != 0) {
                temp = 1;
            }
//            kafkaJson.put("on", temp);
            kafkaJson.put("status", temp);
            kafkaService.emitDeviceDemand(device.getId(), ConstKafka.DEVICE_TYPE_RejectStrangeCallStatus, kafkaJson, vo.getOpenid());
            updateDevice.set("rejectStrange", temp);
            isUpdate = true;
        } else if (vo.getOpMonitor() != null) {
            //仅限于管理员操作
            if(!accountService.checkAccountIsAdminWithImei(vo.getOpenid(), imei)){
                //仅限于管理员操作  API.request.onlyAdminOperation
                return ResponseMap.fail(ResponseEnum.STATUS403.getCode(), "API.request.onlyAdminOperation");
            }
            kafkaJson.put("phone", vo.getOpMonitorPhone());
            kafkaService.emitDeviceDemand(device.getId(), ConstKafka.DEVICE_TYPE_Monitor, kafkaJson, vo.getOpenid());
            accountService.updateById(vo.getOpenid(), new Update().set("phone_m", vo.getOpMonitorPhone()));
        } else if (vo.getOpSettingVolume() != null) {
            kafkaJson.put("volume", vo.getOpSettingVolume());
            kafkaService.emitDeviceDemand(device.getId(), ConstKafka.DEVICE_TYPE_Volume, kafkaJson, vo.getOpenid());
            updateDevice.set("volume", vo.getOpSettingVolume());
            isUpdate = true;
        } else if (vo.getOpRequireLocation() != null) {
            kafkaJson.put("openid", vo.getOpenid());
            kafkaService.emitDeviceDemand(device.getId(), ConstKafka.DEVICE_TYPE_RequestLocation, kafkaJson, vo.getOpenid());
        } else if (vo.getOpLocationMode() != null) {
            if (vo.getOpLocationMode() == 0) {
                kafkaJson.put("second", 7200);
            } else if (vo.getOpLocationMode() == 1) {
                kafkaJson.put("second", 3600);
            } else if (vo.getOpLocationMode() == 2) {
                kafkaJson.put("second", 1800);
            } else if(vo.getOpLocationMode() == 3) {
                kafkaJson.put("second", 60000);
            } else {
                return ResponseMap.fail(String.format("bad opLocationMode: %s, must in [0,1,2]", vo.getOpLocationMode()));
            }
            kafkaService.emitDeviceDemand(device.getId(), ConstKafka.DEVICE_TYPE_LocationUploadInterval, kafkaJson, vo.getOpenid());
            updateDevice.set("locMode", vo.getOpLocationMode());
            isUpdate = true;
        } else if (vo.getOpLocationModeMin() != null) {
            if (vo.getOpLocationModeMin() < 0 || vo.getOpLocationModeMin() > 60) {
                return ResponseMap.fail(String.format("bad opLocationModeMin: %s, must in [0,60]", vo.getOpLocationModeMin()));
            } else {
                kafkaJson.put("second", (vo.getOpLocationModeMin()*60) );
            }
            kafkaService.emitDeviceDemand(device.getId(), ConstKafka.DEVICE_TYPE_LocationUploadInterval, kafkaJson, vo.getOpenid());
            updateDevice.set("locModeMin", vo.getOpLocationModeMin());
            isUpdate = true;
        } else if (vo.getOpPowerOff() != null) {
            //仅限于管理员操作
            if(!accountService.checkAccountIsAdminWithImei(vo.getOpenid(), imei)){
                //仅限于管理员操作  API.request.onlyAdminOperation
                return ResponseMap.fail(ResponseEnum.STATUS403.getCode(), "API.request.onlyAdminOperation");
            }
            kafkaService.emitDeviceDemand(device.getId(), ConstKafka.DEVICE_TYPE_PowerOff, kafkaJson, vo.getOpenid());
        } else if (vo.getOpPhoto() != null) {
            String temp = device.getWatchCustomFunction();
            if (StringUtil.isBlank(temp)) {
                temp = device.getModules();
            }
            if (StringUtil.isBlank(temp) || temp.contains("P0")) {
                kafkaService.emitDeviceDemand(device.getId(), ConstKafka.DEVICE_TYPE_DownRemotePhoto, kafkaJson, vo.getOpenid());
            } else {
                return ResponseMap.fail(ResponseEnum.STATUS600.getCode(), "设备不支持拍照功能");
            }
        } else if (vo.getOpDialSwitch() != null) {
            //仅限于管理员操作
            if(!accountService.checkAccountIsAdminWithImei(vo.getOpenid(), imei)){
                //仅限于管理员操作  API.request.onlyAdminOperation
                return ResponseMap.fail(ResponseEnum.STATUS403.getCode(), "API.request.onlyAdminOperation");
            }
            updateDevice.set("dialSwitch", vo.getOpDialSwitch());
            isUpdate = true;
            kafkaJson.put("status", vo.getOpDialSwitch());
            kafkaService.emitDeviceDemand(device.getId(), ConstKafka.DEVICE_TYPE_DialSwitch, kafkaJson, vo.getOpenid());
        } else if (vo.getOpFlower() != null) {
            updateDevice.set("flower", vo.getOpFlower());
            isUpdate = true;
            kafkaJson.put("flower", vo.getOpFlower());
            kafkaService.emitDeviceDemand(device.getId(), ConstKafka.DEVICE_TYPE_flower, kafkaJson, vo.getOpenid());
        } else if (vo.getOpRestart() != null) {
            //仅限于管理员操作
            if(!accountService.checkAccountIsAdminWithImei(vo.getOpenid(), imei)){
                //仅限于管理员操作  API.request.onlyAdminOperation
                return ResponseMap.fail(ResponseEnum.STATUS403.getCode(), "API.request.onlyAdminOperation");
            }
            kafkaService.emitDeviceDemand(device.getId(), ConstKafka.DEVICE_TYPE_opRestart, kafkaJson, vo.getOpenid());
        } else if (vo.getOpReset() != null) {
            //仅限于管理员操作
            if(!accountService.checkAccountIsAdminWithImei(vo.getOpenid(), imei)){
                //仅限于管理员操作  API.request.onlyAdminOperation
                return ResponseMap.fail(ResponseEnum.STATUS403.getCode(), "API.request.onlyAdminOperation");
            }
            if(device.getLossDevStatus() == 1){
                return ResponseMap.fail(ResponseEnum.STATUS6001.getCode(), "API.request.deviceLossingNotReset");
            }
            //恢复出厂设置
            reset(device, vo.getOpenid(), "app");
        } else if (vo.getOpFind() != null) {
            //寻找设备
            //仅限于管理员操作
          /*  if(!accountService.checkAccountIsAdminWithImei(vo.getOpenid(), imei)){
                //仅限于管理员操作  API.request.onlyAdminOperation
                return ResponseMap.fail(ResponseEnum.STATUS403.getCode(), "API.request.onlyAdminOperation");
            }*/
            //如是在上课禁用时段
            if (CollectionUtil.isNotEmpty(device.getDisBanMap())) {
                int day = DateUtil.getWeekOfDate(new Date());
                for (Map.Entry<String, Map<String, Object>> entry : device.getDisBanMap().entrySet()) {
                    Object week = entry.getValue().get("week");
                    Object status = entry.getValue().get("status");
                    if (StringUtil.isNotBlank(status) && "1".equals(status.toString()) && StringUtil.isNotBlank(week)
                            && week.toString().length() > day - 1 && "1".equals(String.valueOf(week.toString().charAt(day - 1)))
                            && StringUtil.isNotBlank(entry.getValue().get("starttime")) && StringUtil.isNotBlank(entry.getValue().get("endedtime"))) {
                        int starttime = Integer.parseInt(entry.getValue().get("starttime").toString().replace(":", ""));
                        int endedtime = Integer.parseInt(entry.getValue().get("endedtime").toString().replace(":", ""));
                        if (DateUtil.getHourAndMinute() >= starttime && DateUtil.getHourAndMinute() <= endedtime) {
                            log.warn("imei:{} 正处于上课禁用状态，无法寻找设备", device.getId());
                            return ResponseMap.fail(ResponseEnum.STATUS6000.getCode(), ResponseEnum.STATUS6000.getMsg());
                        }
                    }
                }
            }
            kafkaService.emitDeviceDemand(device.getId(), ConstKafka.DEVICE_TYPE_Find, kafkaJson, vo.getOpenid());
        } else if (vo.getOpPowerModel() != null){
            //在device 表中存 预留省电状态开关的是 powerModelSW
            updateDevice.set("powerModelSW", vo.getOpPowerModel());
            isUpdate = true;
            // 下发修改预留省电开关的 指令
            kafkaJson.put("powerModelSW", vo.getOpPowerModel());
//            kafkaService.emitDeviceDemand(device.getId(), ConstKafka.DEVICE_TYPE_126, kafkaJson, vo.getOpenid());
        } else if (vo.getLossDevStatus() != null){
            //在device 表中存 设备挂失状态开关的是 lossDevStatus
            updateDevice.set("lossDevStatus", vo.getLossDevStatus());
            isUpdate = true;
            // 下发修改 设备挂失状态开关 指令
            kafkaJson.put("lossDevStatus", vo.getLossDevStatus());
            //操作者
            JSONObject bingUserInfo = new JSONObject(device.getUserMap().get(vo.getOpenid()));

            kafkaJson.put("relationship_image_id", bingUserInfo.getInteger("relationship_image_id"));
            kafkaJson.put("relationship", bingUserInfo.getString("relationship"));
            kafkaJson.put("phone", bingUserInfo.getString("phone"));

//            kafkaService.emitDeviceDemand(device.getId(), ConstKafka.DEVICE_TYPE_128, kafkaJson, vo.getOpenid());
        }
        //TODO 赛诺还有个 opSosSms (SOS短信开关) 和 opLowBat(低电告警开关) 但暂不处理.APP目前无使用到此功能
        //
        if (isUpdate) {
            this.updateById(device.getId(), updateDevice);
        }
        return ResponseMap.success();
    }

    /**
     * 设备重置
     *
     * @param device
     * @param openid
     * @param type   1=app; 2=device; 3=web
     * @time: 2021/2/3 18:24
     * @author: Rock
     * @version 1.0
     */
    public void reset(Device device, String openid, String type) {
        UpdateVO updateDevice = new UpdateVO();
        updateDevice.set("volume", 6);
        updateDevice.set("locMode", 0);
        updateDevice.unset("locModeMin");
        updateDevice.set("rejectStrange", 0);
        updateDevice.set("step", 0);
        updateDevice.set("distance", 0);
        updateDevice.set("calorie", 0);
        if (!"web".equals(type)) {
            if (StringUtil.isNotBlank(device.getWatchStoreChannelId()) || (Const.INT_1.equals(device.getIsWatchCustomFunction())
                    && device.getWatchCustomFunction() != null && device.getWatchCustomFunction().contains("APPM:"))) {
                //恢复应用监管原始状态
                Map<String, String> params = new HashMap<>();
                long timestamp = System.currentTimeMillis();
                String authKey = DigestUtils.md5Hex(Const.MD5_KEY + timestamp).toUpperCase();
                params.put("timestamp", timestamp + "");
                params.put("authKey", authKey);
                String[] imeis = {device.getId()};
                params.put("imeis", JSON.toJSONString(imeis));
                String url = watchStoreChannelUrl + "/getway/regulatory/restoreInitialState";
                String res = HttpReq.sendPostParam(url, params);
                JSONObject json = JSON.parseObject(res);
                if (json != null && new Integer(200).equals(json.getInteger("code"))) {
                    ;
                } else {
                    log.error("恢复应用监管原始状态 失败, 失败response={}", res);
                }
            }
        }

        if (Const.VENDER_20000.equals(device.getVendor())) {
            //备份一份有效数据到reset_device表中
            if (CollectionUtil.isNotEmpty(device.getUserMap())) {
                resetDeviceService.delById(device.getId());
                Document document = this.findDocById(device.getId());
                Date resetTime = new Date();
                DateUtil.hanldeMongoDate(resetTime, 1);
                document.put("reset_time", resetTime);
                document.put("reset_operator", type);
                resetDeviceService.insertOneDoc(document);
            }
        }
        if (CollectionUtil.isNotEmpty(device.getUserMap())) {
            List<Account> accountList = accountService.listByIds(device.getUserMap().keySet());
            for (Account account : accountList) {
                UpdateVO updateAccount = new UpdateVO();
                if (StringUtil.isNotBlank(account.getImei()) && CollectionUtil.isNotEmpty(account.getDeviceMap())) {
                    if (account.getImei().equals(device.getId())) {
                        //ime 号登录账号
                        //清除所有人的关系
                        List<Device> deviceList = this.listByIds(account.getDeviceMap().keySet());
                        for (Device aDevice : deviceList) {
                            if (!device.getId().equals(aDevice.getId())) {
                                UpdateVO updateD = new UpdateVO();
                                if (account.getDeviceMap().size() > 1) {
                                    CollectionUtil.removeMapKey(account.getDeviceMap(), aDevice.getId());
                                    updateAccount.setMap("d", account.getDeviceMap());
                                }
                                if (CollectionUtil.isNotEmpty(aDevice.getUserMap())) {
                                    if (aDevice.getUserMap().size() == 1) {
                                        updateD.unset("u");
                                        updateD.unset("g");
                                        updateD.unset("checked_openids");
                                        this.updateById(aDevice.getId(), updateD);
                                        continue;
                                    } else {
                                        CollectionUtil.removeMapKey(aDevice.getUserMap(), account.getId());
                                        updateD.setMap("u", aDevice.getUserMap());
                                    }
                                }
                                if (aDevice.getUserMap() != null && aDevice.getUserMap().size() > 1) {
                                    Set<String> delKey = new HashSet<>();
                                    for (Map.Entry<String, Map<String, Object>> entry : aDevice.getUserMap().entrySet()) {
                                        if (account.getId().equals(entry.getValue().get("openid"))) {
                                            //删除checked_openids
                                            CollectionUtil.removeMapKey(aDevice.getCheckedOpenidsMap(), entry.getKey());
                                            delKey.add(entry.getKey());
                                        }
                                    }
                                    for (String key : delKey) {
                                        //删除绑定用户 u
                                        aDevice.getUserMap().remove(key);
                                    }
                                    updateD.setMap("u", aDevice.getUserMap());
                                    updateD.setMap("checked_openids", aDevice.getCheckedOpenidsMap());
                                }
                                this.updateById(aDevice.getId(), updateD);
                            }
                        }
                    } else {
                        //只清除自己的关系
                        CollectionUtil.removeMapKey(account.getDeviceMap(), device.getId());
                    }
                    updateAccount.setMap("d", account.getDeviceMap());
                }

                if (new Integer(4).equals(account.getWxgzIdent())) {
                    if (CollectionUtil.isNotEmpty(account.getDeviceMap())) {
                        if (device.getId().equals(account.getWxgzChatImei())) {
                            if (account.getDeviceMap().size() == 1) {
                                updateAccount.unset("wxgz_chat_imei");
                            } else {
                                for (String key : account.getDeviceMap().keySet()) {
                                    if (!key.equals(account.getWxgzChatImei())) {
                                        updateAccount.set("wxgz_chat_imei", key);
                                    }
                                }
                            }
                        }
                    } else {
                        updateAccount.unset("wxgz_chat_imei");
                    }
                    String content = MessageUtils.getLocale("API.pushTitle.deviceResetNotification",
                            getDeviceName(device));
                    boolean send = weixinService.replyWxMsg(Constant.WEIXIN_PUSH_TYPE_1, content, account.getWxgzMasterId(), account.getWxid());
                    if (!send) {
                        log.error("恢复出厂推送失败,imei={}", device.getId());
                    }
                }
                if (!device.getId().equals(account.getImei())) {
                    CollectionUtil.removeMapKey(account.getDeviceMap(), device.getId());
                }
                //更新操作
                accountService.updateById(account.getId(), updateAccount);
                //如果是设备恢复出厂设置,那么发送推送通知绑定的用户
                if(type.equals("device")){
                    String groupid = device.getChatGroupMap().keySet().toArray()[0].toString();
                    log.info("推送给用户{} imei: {}, 推送类型为 chatGroupDisband groupid:{}", account.getId(), device.getId(), groupid);
                    JSONObject pushObject = new JSONObject();
                    pushObject.put("type", ConstPush.CHAT_GROUP_DISBAND);
                    pushObject.put("imei", device.getId());
                    pushObject.put("groupid", groupid);
                    pushObject.put("operator", openid);
                    pushObject.put("openid", account.getId());
                    String deviceName = this.getDeviceName(device);
                    pushObject.put("name", deviceName);
                    pushObject.put("disbandTime", DateUtil.nowTimestampToLong());
                    // 手表【%s】的管理员将手表恢复出厂设置
                    String msgTitle = MessageUtils.getLocale("API.pushTitle.adminResetDevNotification", deviceName);
                    log.info("-------------------msgTitle-------------:"+msgTitle);
                    pushObject.put("msgTitle", msgTitle);
                    kafkaService.sendPushToAccount(ConstKafka.ACCOUNT_TYPE_3, account.getId(), pushObject);
                }
            }
        }
        //删除设备字段 U
        updateDevice.unset("u");

        //清除 多群聊的 群组
        if (CollectionUtil.isNotEmpty(device.getChatGroupMap())) {
            List<ChatGroup> chatGroupList = chatGroupService.listByIds(CollectionUtil.stringToObjectId(device.getChatGroupMap().keySet()));
            for (ChatGroup chatGroup : chatGroupList) {
                updateDevice.unset(chatGroup.getId());
                CollectionUtil.removeMapKey(chatGroup.getDeviceMap(), device.getId());
                if (!CollectionUtil.isNotEmpty(chatGroup.getDeviceMap())) {
                    if (CollectionUtil.isNotEmpty(chatGroup.getMemberMap())) {
                        List<Account> accountList = accountService.listByIds(chatGroup.getMemberMap().keySet());
                        for (Account account : accountList) {
                            UpdateVO updateA = new UpdateVO();
                            if (device.getId().equals(account.getImei())) {
                                if (StringUtil.isNotBlank(account.getAccesstoken())) {
                                    redisClusterService.del(CacheEnum.UA.getKey() + account.getAccesstoken());
                                }
                                log.info("account deleted= {}", account.getId());
                                accountService.delById(account.getId());
                            } else {
                                if (CollectionUtil.removeMapKey(account.getChatGroupMap(), chatGroup.getId())) {
                                    updateA.setMap("g", account.getChatGroupMap());
                                    updateA.unset(chatGroup.getId());
                                }
                                if (CollectionUtil.removeMapKey(account.getDeviceMap(), device.getId())) {
                                    updateA.setMap("d", account.getDeviceMap());
                                }
                                accountService.updateById(account.getId(), updateA);
                            }
                        }
                    }
                    //删除群组
                    chatGroupService.del(chatGroup.getId(), openid);
                } else {
                    //更新
                    chatGroupService.updateById(new ObjectId(chatGroup.getId()), new Update().set("d", chatGroup.getDeviceMap()));
                }
            }
        }
        //清除 单群聊的 群组
        singleChatGroupService.delByImei(device.getId());
        // =====注意,这里上面的 群聊/单聊 都没有清除聊天消息的数据,
        // 因为聊天数据多的问题,会引起恢复出厂缓慢,
        // 所以交由 脚本定时去mongo数据库中清除过期的聊天记录消息 或者 设置过期时间 expiryAt (mongo中需要设置TTL索引)

        updateDevice.unset("g");
        updateDevice.unset("checked_openids");
        updateDevice.unset("wifis");
        updateDevice.unset("navigation");
        updateDevice.set("targetStep", Const.DEF_TARGET_STEP);
        if (StringUtil.isNotBlank(device.getDialSwitch())) {
            //恢复出厂设置后 默认拨号盘打开
            updateDevice.set("dialSwitch", 1);
        }
        //置空小红花
        updateDevice.set("flower", 0);
        //置空物联网卡号的标记
        updateDevice.unset("iccid");
        updateDevice.unset("isIOTCard");

        updateDevice.unset("s");
        updateDevice.unset("c");
        updateDevice.unset("r");
        updateDevice.unset("va");
        updateDevice.unset("loc");
        updateDevice.unset("nowloc");
        updateDevice.unset("disBan");
        updateDevice.unset("name");
        //===功能开关状态===
        updateDevice.unset("powerModelSW");
        //把预留省电状态 去掉
        updateDevice.unset("powerModel");
        updateDevice.unset("asoStatus");
        updateDevice.unset("sedentaryStatus");
        updateDevice.unset("cmsgStatus");
        updateDevice.unset("lossDevStatus");
        updateDevice.unset("OTAStatus");
        updateDevice.unset("useMobileData");
        //===============
        if("web".equals(type)){
            // web 售后人员的恢复出厂设置的
            // 当设备没有 token 时, APP访问就会提示 "设备未联网激活，请先插卡联网激活", 后台重置后 把token也移除
            updateDevice.unset("token");
            updateDevice.unset("ttime");

        }else{
            updateDevice.set("token", RandomUtil.getRandom(100000, 888888));
            updateDevice.set("ttime", DateUtil.nowTimestampToDouble());
        }
        updateDevice.set("phone", "");
        updateDevice.set("grade", "");
        updateDevice.set("birthday", "");
        updateDevice.set("image", Const.DEFAULT_JPG);
        updateDevice.unset("sex");
        this.updateById(device.getId(), updateDevice);
        //清除今日上传记录
        String dateStr = DateUtil.dateToStr(new Date(), "yyyyMMdd");
        //今天的 上传个数
        redisFilterService.del(deviceSanWordService.deviceSanWordUpdateDayCountKey + device.getId() + "&" + dateStr);
        //回复出厂设置
        deviceResetAsyncService.handleResetDevEvents(device, openid, type);
        //需要清除OSS上存储的设备图片
        if (StringUtil.isNotBlank(device.getImage()) && !device.getImage().contains("default.jpg")) {
            //删除旧文件
            baseBucketTool.delFile(BaseBucketTool.DEVICE_COMMON_PATH + device.getImage());
        }
        //清除通话记录
        callRecordService.delByImei(device.getId());
        //清除短信上报的记录
        deviceCmsgService.delByImei(device.getId());
        if(ObjectUtils.isNotEmpty(device.getIsNewWechatProtocol()) && device.getIsNewWechatProtocol().equals(1)){
            //清除绑定的微聊联系人记录
            wechatContactService.delByImei(device.getId());
        }
        //清除设备监管的数据
        deviceAppManagerService.delByImei(device.getId());
        log.info("reset end. imei = {}", device.getId());
    }

    /**
     * 发送设备验证码
     *
     * @param imei
     * @time: 2021/2/3 18:56
     * @author: Rock
     * @version 1.0
     */
    public ResponseMap sendAuthCode(String imei) {
        Device device = this.findById(imei);
        if (device == null) {
            log.warn("Device is null. id={}. sendAuthCode", imei);
            return ResponseMap.fail(ResponseEnum.STATUS2001.getCode(), ResponseEnum.STATUS2001.getMsg(), imei);
        }
        if (Const.INT_1.equals(device.getPowerModel())) {
            return ResponseMap.fail(ResponseEnum.STATUS5003.getCode(), ResponseEnum.STATUS5003.getMsg());
        }
        String token = redisClusterService.hget(imei, ConstCacheField.TOKEN);
        JSONObject kafkaJson = new JSONObject();
        if (StringUtil.isBlank(token)) {
            if (StringUtil.isBlank(device.getToken())) {
                return ResponseMap.fail(ResponseEnum.STATUS600.getCode(), ResponseEnum.STATUS600.getMsg());
            }
            kafkaJson.put("token", device.getToken());
        } else {
            kafkaJson.put("token", token);
        }
        kafkaService.emitDeviceDemand(imei, ConstKafka.DEVICE_TYPE_AuthCode, kafkaJson, null);
        return ResponseMap.success();
    }

    /**
     * 获取sos号码列表
     *
     * @param imei
     * @time: 2021/2/4 10:46
     * @author: Rock
     * @version 1.0
     */
    public ResponseMap getSos(String imei) {
        Device device = this.findById(imei);
        if (device == null) {
            log.error("Device is null. id={}. getSos", imei);
            return ResponseMap.fail(ResponseEnum.STATUS2001.getCode(), ResponseEnum.STATUS2001.getMsg(), imei);
        }
        List<Object> sosList = new ArrayList<>();
        if (CollectionUtil.isNotEmpty(device.getSos())) {
            for (Map.Entry<String, Map<String, Object>> entry : device.getSos().entrySet()) {
                Map<String, Object> temp = new HashMap<>();
                temp.put("id", entry.getKey());
                temp.put("phone", entry.getValue().get("phone"));
                sosList.add(0, temp);
            }
        }
        ResponseMap res = ResponseMap.success();
        res.put("sos", sosList);
        return res;
    }

    /**
     * 添加sos号码列表
     *
     * @param imei
     * @param vo
     * @time: 2021/2/4 11:07
     * @author: Rock
     * @version 1.0
     */
    public ResponseMap addSos(String imei, PhoneParamReqVO vo) {
        Device device = this.findById(imei);
        if (device == null) {
            log.error("Device is null. id={}. addSos vo={}", imei, vo);
            return ResponseMap.fail(ResponseEnum.STATUS2001.getCode(), ResponseEnum.STATUS2001.getMsg(), imei);
        }
        if (device.getSos() == null) {
            device.setSos(new HashMap<>());
        }
        Map<String, Object> temp = new HashMap<>();
        temp.put("phone", vo.getPhone());
        temp.put("t", DateUtil.nowTimestampToDouble());
        String idKey = RandomUtil.getRandomStr(8);
        device.getSos().put(idKey, temp);
        this.updateById(imei, new Update().set("s", device.getSos()));
        syncSos(imei, device.getSos(), vo.getOpenid());
        ResponseMap res = ResponseMap.success();
        res.put("id", idKey);
        return res;
    }

    /**
     * @param imei
     * @param sos
     * @time: 2021/2/4 11:01
     * @author: Rock
     * @version 1.0
     */
    private void syncSos(String imei, Map<String, Map<String, Object>> sos, String openid) {
        if (sos == null) {
            sos = new HashMap<>();
        }
        List<Object> sosList = new ArrayList<>();
        //防止一下 首个SOS 号码为空
        for (Map.Entry<String, Map<String, Object>> entry : sos.entrySet()) {
            String phone = entry.getValue().get("phone").toString();
            if (StringUtils.isNotBlank(phone)) {
                sosList.add(0, phone);
            }
        }
        if (sosList.size() != sos.size()) {
            int num = sos.size() - sosList.size();
            for (int i = 0; i < num; i++) {
                sosList.add("");
            }
        }
        JSONObject data = new JSONObject();
        data.put("sos", sosList);
        kafkaService.emitDeviceDemand(imei, ConstKafka.DEVICE_TYPE_SOS, data, openid);
    }

    /**
     * 修改sos号码
     *
     * @param imei
     * @param vo
     * @time: 2021/2/4 11:23
     * @author: Rock
     * @version 1.0
     */
    public ResponseMap updateSos(String imei, UpdateSosReqVO vo) {
        Device device = this.findById(imei);
        if (device == null || !CollectionUtil.isNotEmpty(device.getSos())) {
            log.error("Device or sos is null. id={}", imei);
            return ResponseMap.fail();
        }
        JSONArray idJsonArr = JSON.parseArray(vo.getIds());
        JSONArray phoneJsonArr = JSON.parseArray(vo.getPhones());
        if (idJsonArr.size() != phoneJsonArr.size()) {
            return ResponseMap.fail();
        }
        for (int i = 0; i < idJsonArr.size(); i++) {
            if (device.getSos().containsKey(idJsonArr.getString(i))) {
                device.getSos().get(idJsonArr.getString(i)).put("phone", phoneJsonArr.getString(i));
            }
        }
        this.updateById(imei, new Update().set("s", device.getSos()));
        syncSos(imei, device.getSos(), vo.getOpenid());
        return ResponseMap.success();
    }

    /**
     * 删除sos号码
     *
     * @param imei
     * @param vo
     * @time: 2021/2/4 11:27
     * @author: Rock
     * @version 1.0
     */
    public ResponseMap delSos(String imei, IdParamReqVO vo) {
        Device device = this.findById(imei);
        if (device == null) {
            log.error("Device is null. id={}. delSos vo={}", imei, vo);
            return ResponseMap.fail(ResponseEnum.STATUS2001.getCode(), ResponseEnum.STATUS2001.getMsg(), imei);
        }
        if (CollectionUtil.removeMapKey(device.getSos(), vo.getId())) {
            this.updateById(device.getId(), new UpdateVO().setMap("s", device.getSos()));
            syncSos(imei, device.getSos(), vo.getOpenid());
        }
        return ResponseMap.success();
    }


    /**
     * 查/改自动接通状态及成员列表
     * @param imei
     * @param vo
     * @time: 12/13/21 4:04 PM
     * @author: Weichao
     * @version 1.0
     */
    public ResponseMap aso(String imei, AsoReqVO vo) {
        Device device = this.findById(imei);
        Integer asoStatus = device.getAsoStatus();
        JSONObject res = new JSONObject();
        if(vo.getOption().equals("get")){
            //查
            res.put("status", asoStatus);
            List<Map<String, Object>> list = new ArrayList<>();
            if (CollectionUtil.isNotEmpty(device.getUserMap())) {
                for (Map.Entry<String, Map<String, Object>> entry : device.getUserMap().entrySet()) {
                    Map<String, Object> temp = new HashMap<>();
                    temp.put("id", entry.getKey());
                    temp.put("relationship", entry.getValue().get("relationship"));
                    temp.put("phone", entry.getValue().get("phone"));
                    temp.put("time", StringUtil.isNumeric(entry.getValue().get("t")) ? new Double(entry.getValue().get("t").toString()) : 0);
                    temp.put("relationship_image_id", entry.getValue().get("relationship_image_id"));
                    // 默认如果没有字段的 默认是 1,添加关联的联系人是是自动添加进去的
                    temp.put("asoSelect", (entry.getValue().get("asoSelect") == null) ? 1 : Integer.valueOf(entry.getValue().get("asoSelect").toString()));
                    list.add(temp);
                }
                //根据time降序排序
                CollectionUtil.sortDouble(list, "time", 2);
            }

            res.put("aso",list);
        }else if (vo.getOption().equals("change")){
            //改
            UpdateVO updateVO = new UpdateVO();
            Integer changStatus = vo.getStatus();
            if(changStatus.intValue() != asoStatus.intValue()){
                updateVO.set("asoStatus", changStatus);
            }
            JSONArray ids = JSONArray.parseArray(vo.getIds());
            JSONArray asoList = new JSONArray();
            if (CollectionUtil.isNotEmpty(device.getUserMap())) {
                for (Map.Entry<String, Map<String, Object>> entry : device.getUserMap().entrySet()) {
                    String id = entry.getKey();
                    Map<String, Object> idValue = entry.getValue();
                    if(ids.contains(id)){
                        idValue.put("asoSelect", 1);
                        JSONObject temp = new JSONObject();
                        temp.put("relationship", idValue.get("relationship").toString());
                        temp.put("relationship_image_id", Integer.valueOf(idValue.get("relationship_image_id").toString()));
                        temp.put("phone", idValue.get("phone").toString());
                        if(changStatus != 0){
                            //打开时才需要下发
                            asoList.add(temp);
                        }
                    }else{
                        idValue.put("asoSelect", 0);
                    }
                }
            }
            updateVO.setMap("u", device.getUserMap());
            this.updateById(device.getId(), updateVO);
            // 下发修改代收短信开关的 指令
            JSONObject kafkaJson = new JSONObject();
            kafkaJson.put("asoList", asoList);
//            kafkaService.emitDeviceDemand(imei, ConstKafka.DEVICE_TYPE_120, kafkaJson);
        }

        return ResponseMap.success(res);
    }

    /**
     * 查 设备OTA升级信息
     * @param imei
     * @param vo
     * @time: 1/6/22 3:10 PM
     * @author: Weichao
     * @version 1.0
     */
    public ResponseMap remoteUpGet(String imei, DeviceRemoeOTAReqVO vo) {
        JSONObject res = new JSONObject();
        Device device = this.findById(imei);
        Integer haveWIFI = 0;
        if (device.getWatchCustomFunction() != null) {
            String [] tempStrArr = device.getWatchCustomFunction().split("OTA_");
            if(tempStrArr.length > 1){
                //是否有WIFI版本
                haveWIFI = Integer.valueOf(tempStrArr[1].split(",")[0]);
            }
        }

        res.put("OTAStatus", device.getOTAStatus());
        res.put("useMobileData", device.getUseMobileData());
        res.put("haveWIFI", haveWIFI);
        res.put("curVersion", device.getVersion());

        String desContent = MessageUtils.getLocale("API.request.OTAVersion.failDes");
        try{
            JSONObject params = new JSONObject();
            long timestamp = DateUtil.nowTimestampToLong();

            JSONObject devModelInfoOB = JSONObject.parseObject(ALB_OTADevModelMapJSONStr);
            String productId = "";
            String deviceId = "";
            String deviceSecret = "";
            String defMid = "";
            String version = device.getVersion();
            String devModel = device.getDevModel();
            if(version != null && devModel != null){
                for (String key :devModelInfoOB.keySet()) {
                    if(key.contains(devModel)){
                        JSONObject item = devModelInfoOB.getJSONObject(key);
                        productId = item.getString("productId");
                        deviceId = item.getString("deviceId");
                        deviceSecret = item.getString("deviceSecret");
                        defMid = item.getString("defMid");
                    }
                }
                if(deviceId.length()>0 && deviceSecret.length()>0 && productId.length()>0){
                    String inputStr = String.format("%s%s%s", deviceId, productId, timestamp);
                    byte[] inputData = inputStr.getBytes();
                    String signStr = SignUtil.byteArrayToHexString(SignUtil.encryptHMAC(inputData, deviceSecret, SignUtil.HmacMD5));

                    String url = String.format(ALB_OTAVersionReqURL,productId,deviceId);
                    params.put("timestamp", timestamp);
                    params.put("sign", signStr);
                    params.put("mid", defMid);
                    params.put("version", version);
                    String otaResJOSNStr = HttpReq.sendPostJson(url, params.toJSONString());
                    JSONObject resOB = JSONObject.parseObject(otaResJOSNStr);
                    if(resOB.getInteger("status") == 1000){
                        //成功
                        JSONObject releaseNotes = resOB.getJSONObject("data").getJSONObject("releaseNotes");
                        //升级包大小，单位 Byte
                        int fileSize = resOB.getJSONObject("data").getJSONObject("version").getIntValue("fileSize");
                        //最新版本更新发布的日期
                        String publishDate = releaseNotes.getString("publishDate");
                        //最新版本
                        String newVersion = releaseNotes.getString("version");
                        //最新版本更新说明
                        String newVersionDesContent = JSONArray.parseArray(releaseNotes.getString("content")).getJSONObject(0).getString("content");
                        desContent = MessageUtils.getLocale("API.request.OTAVersion.successDes",
                                newVersion,
                                publishDate,
                                newVersionDesContent,
                                String.format("%.02fM",fileSize/1000.0/1024)
                        );
                    }
                }
            }

        }catch (Exception error){
            log.error("获取 艾拉比OTA 固件版本信息时出错:"+error.getMessage(), error);
        }

//        String desContent = String.format("检查到最新版本:%s \n升级说明:\n%s \n1.手表会在充电且连接Wi-Fi时下载安装包，并完成升级； \n2.本次安装包大小为%s",
//                "newV_10086.01.06.1635",
//                "最新版本更新说明",
//                "10000000M"
//                );
        res.put("desContent", desContent);

        return ResponseMap.success(res);
    }

    /**
     * 改 设备OTA升级信息
     * @param imei
     * @param vo
     * @time: 1/6/22 3:10 PM
     * @author: Weichao
     * @version 1.0
     */
    public ResponseMap remoteUpPost(String imei, DeviceRemoeOTAReqVO vo) {


        //检测一下是否有更改
        Device device = this.findById(imei);
        if( device.getOTAStatus().intValue() != vo.getOTAStatus().intValue() ||
                device.getUseMobileData().intValue() != vo.getUseMobileData().intValue() ) {
            UpdateVO updateVO = new UpdateVO();
            updateVO.set("OTAStatus", vo.getOTAStatus());
            //下发 修改指令 130
            JSONObject kafkaJson = new JSONObject();
            kafkaJson.put("OTAStatus", vo.getOTAStatus());
            if(vo.getOTAStatus() == 0){
                updateVO.set("useMobileData", 0);
                kafkaJson.put("useMobileData", 0);
            }else{
                updateVO.set("useMobileData", vo.getUseMobileData());
                kafkaJson.put("useMobileData", vo.getUseMobileData());
            }
//            kafkaService.emitDeviceDemand(imei, ConstKafka.DEVICE_TYPE_130, kafkaJson);
            this.updateById(imei, updateVO);

        }else{
            log.info("imei:{} POST修改设备OTA升级信息 和原本信息保持不变, 无需进行指令下发和修改数据库", imei);
        }
        return ResponseMap.success();
    }


    /**
     * 查 设备挂失信息
     * @param imei
     * @param vo
     * @time: 1/6/22 3:10 PM
     * @author: Weichao
     * @version 1.0
     */
    public ResponseMap lossDevGet(String imei, BaseAccountReqVO vo) {
        JSONObject res = new JSONObject();
        Device device = this.findById(imei);
        String desContent = "";
        if(device.getLossDevStatus() == 1){
            //操作者
            JSONObject bingUserInfo = new JSONObject(device.getUserMap().get(vo.getOpenid()));
            desContent = MessageUtils.getLocale("API.request.deviceLossingShowDes",
                    bingUserInfo.getString("relationship"),
                    bingUserInfo.getString("phone"));

        }
        res.put("lossDevStatus", device.getLossDevStatus());
        res.put("desContent", desContent);
        return ResponseMap.success(res);
    }

    /**
     * @param device
     * @time: 2021/3/9 10:36
     * @author: Rock
     * @version 1.0DEFAULT_DEVICE_NAME
     */
    public String getDeviceName(Device device) {
        if (StringUtil.isBlank(device.getName())) {
            if (Const.INT_1.equals(device.getDevOrientGroup()) || new Integer(2).equals(device.getDevOrientGroup())) {
                //成人
                return "未设置昵称";
            } else {
                //儿童
                return Const.DEFAULT_DEVICE_NAME;
            }
        }
        return device.getName();
    }


    /**
     * @description 查询单个代收短信的状态信息
     * @author cwj
     * @param [imei]
     * @return java.lang.Integer
     * @date @time 2024/12/17 10:49
     **/
    public Integer queryCmsgStatusByImei(String imei){
        Query query = new Query(Criteria.where("_id").is(imei));
        query.fields().include("cmsgStatus").exclude("_id"); // 只查询cmsgStatus，并排除 _id
        JSONObject data = mongoTemplate.findOne(query,JSONObject.class,"device");
        return data.getInteger("cmsgStatus");
    }
    
    
    /**
     * @description 更新设备的代收短信的状态
     * @author cwj
     * @param [imei]
     * @return void
     * @date @time 2024/12/24 13:47
     **/
    public void updateCmsgStatusById(String imei){
        Integer cmsgStatus = queryCmsgStatusByImei(imei);
        if(ObjectUtils.isEmpty(cmsgStatus) || cmsgStatus.equals(0)){
            Update update = new Update();
            update.set("cmsgStatus",1);
            this.updateById(imei,update);
        }
    }


    /**
     * @description 设置夜间省电模式的状态
     * @author cwj
     * @param [vo]
     * @return com.iot08.common.utils.response.ResponseMap
     * @date @time 2025/5/4 17:23
     **/
    public ResponseMap settingPowerSaving(PowerSavingModeReqVo vo){
        //检查设备是否在线，不在线不能下发
        String onlineStatus = redisClusterService.hget(vo.getImei(), ConstCacheField.ONLINE_STATUS);
        if (!"1".equals(onlineStatus)) {
            return ResponseMap.fail(ResponseEnum.STATUS5001.getCode(), ResponseEnum.STATUS5001.getMsg());
        }
        Device device = this.findById(vo.getImei());
        if (device == null) {
            log.error("Device is null. _id={}", vo.getImei());
            return ResponseMap.fail(ResponseEnum.STATUS2001.getCode(), ResponseEnum.STATUS2001.getMsg(), vo.getImei());
        }
        //更新设备夜间省电模式的状态
        Update update = new Update();
        update.set("powerSavingModeStatus",vo.getPowerSavingModeStatus());
        this.updateById(vo.getImei(),update);
        //发送设置夜间省电模式状态的指令
        JSONObject kafkaJson = new JSONObject();
        kafkaJson.put("yjStatus", vo.getPowerSavingModeStatus());
        kafkaService.emitDeviceDemand(vo.getImei(), ConstKafka.POWER_SAVING_STATUS, kafkaJson,vo.getOpenid());
        return ResponseMap.success();
    }

    /**
     * @description 查询设备省电模式的状态
     * @author cwj
     * @param [vo]
     * @return com.iot08.common.utils.response.ResponseMap
     * @date @time 2025/5/4 18:02
     **/
    public ResponseMap queryPowerSavingMode(PowerSavingModeQueryReqVo vo){
        Device device = this.findById(vo.getImei());
        if (device == null) {
            log.error("Device is null. _id={}", vo.getImei());
            return ResponseMap.fail(ResponseEnum.STATUS2001.getCode(), ResponseEnum.STATUS2001.getMsg(), vo.getImei());
        }
        ResponseMap res = ResponseMap.success();
        res.put("powerSavingModeStatus",ObjectUtils.isNotEmpty(device.getPowerSavingModeStatus())?device.getPowerSavingModeStatus():0);
        return res;
    }



    public static void main(String[] args) {
        DeviceService temp = new DeviceService();
        Device tempDev = new Device();
        tempDev.setIsWatchCustomFunction(1);
        tempDev.setWatchCustomFunction("TK,AB,CK,DND,ML,SNTS,HTF,RS,SOS,GF,RESET,L3,P0,PPMF,CF,DW,,DF,APPM:6");
//        tempDev.setWatchCustomFunction("TK,AB,CK,DND,ML,SNTS,HTF,RS,SOS,GF,RESET,L3,S0,P0,PPMF,DF,CF,DW,ALIPAY,H_HR,H_BP,H_BO,V_MONITO");
        JSONObject tempData = new JSONObject();
        tempData.put("support_video", 5);
        temp.checkDeviceFunctions(tempDev, tempData);
        System.out.println(String.format("tempData:" + tempData.toJSONString()));

        Double t = Double.valueOf("1.63816541804E9");
        Date updateDate = new Date(t.longValue() * 1000);
        System.out.println(String.format("t:{}, updateDate:{}", t, updateDate));
    }

}
